poj 3160 Father Christmas flymouse (SCC缩点+SPFA求最长路)

来源:互联网 发布:windows自带桌面图片 编辑:程序博客网 时间:2024/05/18 01:46

题目大意:一个有向图,每个顶点有一个权值(可正可负),现在从某个顶点出发,求所能获得的最大权值。当经过某个顶点时可以选择加上该顶点的权值或者不加,且一个顶点的权值只能够被加一次,顶点可重复访问。


建模:显然对于权为负的顶点是不加的,对于一个强连通分支,要使获得的权值最大,所有的正权都应当算上。于是可以把原图进行缩点,对于每一个强连通分量其权值为内部点的正权值之和。缩点后得到一个DAG图,用SPFA求最长路即可。这里有个技巧,就是加一个源点,另其权值为0,对于DAG图每个顶点连一条边。这样只需以该源点为起点,求一次SPFA就可以得到从各个顶点出发获得的最大值。


#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<vector>#include<stack>#include<queue>using namespace std;#define N 30005struct Edge{    int to,next;}edge[150005];int cnt,head[N],low[N],dfn[N],dfs_clock,scc_cnt,sccno[N],val[N],v[N];vector<int>scc[N];stack<int>S;void dfs(int u){    low[u]=dfn[u]=++dfs_clock;    S.push(u);    for(int i=head[u];~i;i=edge[i].next){        int v=edge[i].to;        if(!dfn[v]){            dfs(v);            low[u]=min(low[v],low[u]);        }        else if(!sccno[v]) low[u]=min(low[u],dfn[v]);    }    if(low[u]==dfn[u]){        val[++scc_cnt]=max(0,v[u]);        for(;;){            int x=S.top();S.pop();            sccno[x]=scc_cnt;            if(x==u) break;            val[scc_cnt]+=max(0,v[x]);        }    }}void find_scc(int n){    memset(sccno,0,sizeof(sccno));    memset(dfn,0,sizeof(dfn));    dfs_clock=scc_cnt=0;    for(int i=0;i<n;++i) if(!dfn[i]) dfs(i);}inline void add(int u,int v){    edge[cnt].to=v;    edge[cnt].next=head[u];    head[u]=cnt++;}vector<int>G[N];bool inq[N];int d[N];void spfa(int s){    queue<int>q;    memset(inq,0,sizeof(inq));    memset(d,0,sizeof(d));    inq[s]=1;q.push(s);    while(!q.empty()){        int u=q.front();q.pop();        inq[u]=0;        for(int i=0;i<G[u].size();++i){            int v=G[u][i];            if(d[u]+val[v]>d[v]){                d[v]=d[u]+val[v];                if(!inq[v]){                    inq[v]=1;                    q.push(v);                }            }        }    }}int main(){    int i,j,n,m,x,y;    while(~scanf("%d%d",&n,&m)){        memset(head,-1,sizeof(head));        cnt=0;        for(i=0;i<n;++i) scanf("%d",&v[i]);        for(i=0;i<m;++i){            scanf("%d%d",&x,&y);            add(x,y);        }        find_scc(n);        for(i=1;i<=scc_cnt;++i) {G[i].clear();d[i]=-1;}        for(i=0;i<n;++i)            for(j=head[i];~j;j=edge[j].next){                int v=edge[j].to;                if(sccno[i]!=sccno[v]) G[sccno[i]].push_back(sccno[v]);            }        for(i=1;i<=scc_cnt;++i) G[scc_cnt+1].push_back(i);        int ans=-1;        spfa(scc_cnt+1);        for(i=1;i<=scc_cnt;++i) ans=max(ans,d[i]);        printf("%d\n",ans);    }    return 0;}


0 0
原创粉丝点击