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




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