1. 程式人生 > >BZOJ 1179 (Tarjan縮點+DP)

BZOJ 1179 (Tarjan縮點+DP)

題面

傳送門

分析

由於一個點可以經過多次,顯然每個環都會被走一遍。
考慮縮點,將每個強連通分量縮成一個點,點權為聯通分量上的所有點之和
縮點後的圖是一個有向無環圖(DAG)
可拓撲排序,按照拓撲序進行DP
子狀態:\(dp[i]\)表示以i結尾的路徑的最大權值和
狀態轉移方程 \(dp[y]=max(dp[y],dp[x]+val[y]) ( (x,y) \in E)\)
最終的答案為max(dp[belong[u]]),其中u是酒吧編號,belong[u]表示酒吧所在的聯通分量

程式碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<stack>
#include<map>
#define maxn 500005
using namespace std;
struct edge{
    int u;
    int v;
    edge(){
        
    }
    edge(int from,int to){
        u=from;
        v=to;
    }
    friend bool operator < (edge a,edge b){
        if(a.u==b.u) return a.v<b.v;
        else return a.u<b.u;
    }
};
map<edge,int>used;
int n,m,st,p;
vector<int>G[maxn];
vector<int>D[maxn];
int money[maxn];
int tim=0;
int cnt=0;
int dfn[maxn];
int low[maxn];
int ins[maxn];
int belong[maxn];
long long dp[maxn],val[maxn];
stack<int>s;
void tarjan(int x){
    s.push(x);
    ins[x]=1;
    dfn[x]=low[x]=++tim;
    int t=G[x].size();
    for(int i=0;i<t;i++){
        int y=G[x][i];
        if(!dfn[y]){
            tarjan(y);
            low[x]=min(low[x],low[y]);
        }else if(ins[y]){
            low[x]=min(low[x],dfn[y]);
        }
    }
    if(low[x]==dfn[x]){
        cnt++;
        int y;
        do{
            y=s.top();
            s.pop();
            ins[y]=0;
            val[cnt]+=money[y];
            belong[y]=cnt;
        }while(x!=y);
    }
}

int in[maxn];
int out[maxn];
void graph_to_dag(){
    for(int i=1;i<=n;i++){
        if(!dfn[i]) tarjan(i);
    }
    for(int i=1;i<=n;i++){
        int t=G[i].size();
        for(int j=0;j<t;j++){
            int k=G[i][j];
            if(belong[i]!=belong[k]){
                if(used.count(edge(belong[i],belong[k]))) continue; 
                used[edge(belong[i],belong[k])]=1;
                D[belong[i]].push_back(belong[k]);
                in[belong[k]]++;
            }
        }
    }
}

int is_ok[maxn];
void topo_sort(int s){
    queue<int>q;
    is_ok[s]=1;
    for(int i=1;i<=cnt;i++){
        if(in[i]==0){
            q.push(i);
        }
    }
    dp[s]=val[s];
    while(!q.empty()){
        int x=q.front();
        q.pop();
        int t=D[x].size();
        for(int i=0;i<t;i++){
            int y=D[x][i];
            in[y]--;
            if(is_ok[x]){
                dp[y]=max(dp[y],dp[x]+val[y]);
                is_ok[y]=1;
            }
            if(in[y]==0) q.push(y); 
        }
    }
}

int main(){
    int u,v;
    scanf("%d %d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d %d",&u,&v);
        G[u].push_back(v);
    }
    for(int i=1;i<=n;i++){
        scanf("%d",&money[i]);
    }
    graph_to_dag();
    scanf("%d %d",&st,&p);
    topo_sort(belong[st]);
    long long ans=0;
    for(int i=1;i<=p;i++){
        scanf("%d",&u);
        ans=max(ans,dp[belong[u]]);
    }
    printf("%lld\n",ans);
}