题意:
给一个有n个节点的有向图,每个节点有一个值,现在要在图中遍历一次,遍历到一个点可以取走该点的值,现在求在一次遍历中能取到的最大和。
思路:
用tarjan算法缩点后直接搜索最大值。
代码:
//poj 3160
//sepNINE
#include <iostream>
#include <stack>
using namespace std;
const int maxN=30024;
const int maxM=150048;
int value[maxN],head[maxN],treeHead[maxN],dfn[maxN],low[maxN],ins[maxN],belong[maxN];
int sum[maxN];
stack<int> s;
struct Edge{int v,next;
}edge[maxM],treeEdge[maxM];
int n,m,e,treeE,t,cnt;void tarjan(int u){dfn[u]=low[u]=++t;s.push(u);ins[u]=1;for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].v;if(dfn[v]==0){tarjan(v);low[u]=min(low[u],low[v]);}else if(ins[v]==1)low[u]=min(low[u],dfn[v]); }int k;if(low[u]==dfn[u]){++cnt;do{k=s.top();s.pop();ins[k]=0; belong[k]=cnt;}while(low[k]!=dfn[k]); } return ;
}int dfs(int u)
{int tot=sum[u];int maxx=0;for(int i=treeHead[u];i!=-1;i=treeEdge[i].next){int v=treeEdge[i].v;maxx=max(maxx,dfs(v));} return tot+maxx;
}int main()
{while(scanf("%d%d",&n,&m)==2){int i;e=treeE=0;memset(head,-1,sizeof(head));memset(treeHead,-1,sizeof(treeHead));memset(dfn,0,sizeof(dfn));memset(ins,0,sizeof(ins));memset(sum,0,sizeof(sum));while(!s.empty()) s.pop();for(i=0;i<n;++i) scanf("%d",&value[i]); while(m--){int a,b;scanf("%d%d",&a,&b);edge[e].v=b;edge[e].next=head[a];head[a]=e++;}t=cnt=0;for(i=0;i<n;++i)if(!dfn[i])tarjan(i);for(i=0;i<n;++i)if(value[i]>0)sum[belong[i]]+=value[i];for(i=0;i<n;++i)for(int j=head[i];j!=-1;j=edge[j].next){int u=belong[i],v=belong[edge[j].v];if(u!=v){treeEdge[treeE].v=v;treeEdge[treeE].next=treeHead[u];treeHead[u]=treeE++;}}int ans=0;for(i=1;i<=cnt;++i)ans=max(ans,dfs(i));printf("%d\n",ans); } return 0;
}