当前位置: 代码迷 >> 综合 >> poj 3160 Father Christmas flymouse 强连通分量
  详细解决方案

poj 3160 Father Christmas flymouse 强连通分量

热度:31   发布时间:2024-01-19 06:24:55.0

题意:

给一个有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;	
}