cdoj 1431 不是图论(强联通分量+缩点+拓扑排序+dp)

来源:互联网 发布:鸟叔linux私房菜pdf 编辑:程序博客网 时间:2024/05/22 06:21

不是图论

Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others)
 

给出一个nn个点,mm条边的有向图。每个点上有分值,经过这个点时可以获得一定的分数。

一个点可以经过多次,但是一个点上的分数只能获得一次。

问最多能获得多少分数,起点任选。

1<=nn<=30000,1<=mm<=100000

Input

输入包含多组数据

每组数据第一行为nnmm

接下来nn行,每行有一个数,表示第ii个节点的分值。

接下来mm行,每行有两个数aabb,表示有一条从aabb的有向边

Output

每组数据输出一行,每行仅有一个整数:可以获得的最多的分数。

题解:首先可以把同一个强连通分量看作一个点,分数为分量里点的分数之和,按照拓扑序,跑dp,具体看代码;

#include<bits/stdc++.h>#define MAXN 30005using namespace std;int info[MAXN],info2[MAXN];vector<int> to,to2,NEXT,next2;int STACK[MAXN],dfn[MAXN],low[MAXN],belong[MAXN],instack[MAXN],sc[MAXN],vis[MAXN],ssc[MAXN],dp[MAXN];int cnt,scnt,top,n,m;set<int> st[MAXN];queue<int> q;void add(int u,int v){to.push_back(v);NEXT.push_back(info[u]);info[u]=to.size()-1;}void tarjan(int v){int m,t;dfn[v]=low[v]=++cnt;instack[v]=1;STACK[top++]=v;for(int i=info[v];i!=-1;i=NEXT[i]){int j=to[i];if(!dfn[j]){tarjan(j);low[v]=min(low[v],low[j]);}else if(instack[j])low[v]=min(low[v],dfn[j]);}if(dfn[v]==low[v]){scnt++;do{t=STACK[--top];instack[t]=0;belong[t]=scnt;ssc[scnt]+=sc[t];}while(t!=v);}}void solve(){for(int i=1;i<=n;i++){if(!dfn[i])tarjan(i);}}void init(){memset(info,-1,sizeof(info));memset(info2,-1,sizeof(info2));memset(instack,0,sizeof(instack));memset(ssc,0,sizeof(ssc));to.clear();to2.clear();NEXT.clear();next2.clear();memset(vis,0,sizeof(vis));memset(dfn,0,sizeof(dfn));cnt=scnt=top=0;}int main(){int u,v;while(scanf("%d%d",&n,&m)!=EOF){init();for(int i=1;i<=n;i++)scanf("%d",&sc[i]);for(int i=1;i<=m;i++){scanf("%d%d",&u,&v);add(u,v);}solve();for(int i=1;i<=n;i++){for(int j=info[i];j!=-1;j=NEXT[j]){if(belong[i]!=belong[to[j]]&&!st[i].count(to[j])){int u=belong[i],v=belong[to[j]];to2.push_back(v);next2.push_back(info2[u]);info2[u]=to2.size()-1;st[u].insert(v);}}}for(int i=1;i<=scnt;i++)dp[i]=ssc[i];for(int i=0;i<to2.size();i++)vis[to2[i]]++;for(int i=1;i<=scnt;i++)if(!vis[i])q.push(i);int ans=-1;while(!q.empty()){int u=q.front();q.pop();ans=max(ans,dp[u]);for(int i=info2[u];i!=-1;i=next2[i]){int v=to2[i];dp[v]=max(dp[v],dp[u]+ssc[v]);ans=max(ans,dp[v]);vis[v]--;if(!vis[v])q.push(v);}}printf("%d\n",ans);}return 0;}




0 0
原创粉丝点击