BZOJ1179 APIO2009 Atm 连通性+最短路

题意:给定一张无向图,求1到给定点中,点权和最大的路径

题解:

据说是APIO最水的一道题……Tarjan缩点然后SPFA跑最长路(一开始敲成最短路了QAQ),当然也可以拓扑DP不过更麻烦一些

Tarjan的思路就是像遍历一棵树那样遍历整张图,记录每个节点的编号dfn[i]及其DFS树中子树所能回溯到的最早的节点low[i],如果dfn[i]==low[i],显然其整棵子树上low[x]==low[i]的点全都能回溯到i然后再重新到达其他low[x]==low[i]的点,所以这些点就构成了一个强连通分量。由于DFS序中某点子树是连续的一段,因此可以用栈来记录。

#include <stack>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <climits>
#include <iostream>
#include <algorithm>
using namespace std;

const int MAXN=3000+2;
struct HASH{
    int u;
    HASH *next;
    HASH(){}
    HASH(int _u,HASH *_next):u(_u),next(_next){}
}*table[MAXN],mem[2*MAXN],*node[MAXN];
int N,M,w[MAXN],f[MAXN],S,P,ans=INT_MIN,cnt,d[MAXN];
int dfn[MAXN],low[MAXN],scc,depth;
bool flag[MAXN];
stack<int> s;
queue<int> q;

void Insert1(int u,int v){ table[u]=&(mem[cnt++]=HASH(v,table[u]));}

void Insert2(int u,int v){ node[u]=&(mem[cnt++]=HASH(v,node[u]));}

void Tarjan(int x){
    low[x]=dfn[x]=++depth,flag[x]=1,s.push(x);
    for(HASH *p=table[x];p;p=p->next){
        if(!dfn[p->u]){
            Tarjan(p->u);
            low[x]=min(low[x],low[p->u]);
        }
        else if(flag[p->u]) low[x]=min(low[x],dfn[p->u]);
    }

    if(dfn[x]==low[x]){
        scc++;
        int t=0;
        while(t!=x){
            t=s.top(),s.pop();
            f[t]=scc,flag[t]=0;
        }
    }
}

void SPFA(int s){
    memset(d,-1,sizeof(d));
    memset(flag,0,sizeof(flag));
    q.push(s),d[s]=w[s],flag[s]=1;

    int x;
    while(!q.empty()){
        x=q.front(),q.pop();
        for(HASH *p=node[x];p;p=p->next)
            if(d[p->u]<d[x]+w[p->u]){
                d[p->u]=d[x]+w[p->u];
                if(!flag[p->u]) flag[p->u]=1,q.push(p->u);
            }
        flag[x]=0;
    }
}

int main(){
    cin >> N >> M;
    for(int i=1,u,v;i<=M;i++){
        cin >> u >> v;
        Insert1(u,v);
    }

    for(int i=1;i<=N;i++)
        if(!dfn[i]) Tarjan(i);
    for(int i=1,t;i<=N;i++){
        cin >> t;
        w[f[i]]+=t;
    }
    for(int i=1;i<=N;i++)
        for(HASH *p=table[i];p;p=p->next)
            if(f[i]!=f[p->u]) Insert2(f[i],f[p->u]);

    scanf("%d %d",&S,&P);
    SPFA(f[S]);
    for(int i=1,t;i<=P;i++){
        cin >> t;
        ans=max(ans,d[f[t]]);
    }
    cout << ans << endl;

    return 0;
}
View Code

 

posted @ 2017-02-28 00:08  WDZRMPCBIT  阅读(153)  评论(0编辑  收藏  举报