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

不是图论

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 30005
using 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;
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章