C++強連通分量與SPFA綜合題目—————搶掠計劃

題目描述:

Siruseri 城中的道路都是單向的。不同的道路由路口連接。按照法律的規定, 在每個路口都設立了一個 Siruseri 銀行的 ATM 取款機。令人奇怪的是,Siruseri 的酒吧也都設在路口,雖然並不是每個路口都設有酒吧。

Banditji 計劃實施 Siruseri 有史以來最驚天動地的 ATM 搶劫。他將從市中心 出發,沿着單向道路行駛,搶劫所有他途徑的 ATM 機,最終他將在一個酒吧慶祝他的勝利。

使用高超的黑客技術,他獲知了每個 ATM 機中可以掠取的現金數額。他希望你幫助他計算從市中心出發最後到達某個酒吧時最多能搶劫的現金總數。他可以經過同一路口或道路任意多次。但只要他搶劫過某個 ATM 機後,該 ATM 機 裏面就不會再有錢了。 例如,假設該城中有 6 個路口,道路的連接情況如下圖所示:

市中心在路口 1,由一個入口符號→來標識,那些有酒吧的路口用雙圈來表

示。每個 ATM 機中可取的錢數標在了路口的上方。在這個例子中,Banditji 能搶 劫的現金總數爲 47,實施的搶劫路線是:1-2-4-1-2-3-5。

輸入:

第一行包含兩個整數 N、M。N 表示路口的個數,M 表示道路條數。接下來 M 行,每行兩個整數,這兩個整數都在 1 到 N 之間,第 i+1 行的兩個整數表示第 i 條道路的起點和終點的路口編號。接下來 N 行,每行一個整數,按順序表示每 個路口處的 ATM 機中的錢數。接下來一行包含兩個整數 S、P,S 表示市中心的 編號,也就是出發的路口。P 表示酒吧數目。接下來的一行中有 P 個整數,表示 P 個有酒吧的路口的編號。

輸出:

輸出一個整數,表示 Banditji 從市中心開始到某個酒吧結束所能搶劫的最多 的現金總數。

輸入樣例:

6 7 
1 2 
2 3 
3 5 
2 4 
4 1 
2 6 
6 5 
10 
12 

16 


1 4 
4 3 5 6

輸出樣例:

47

思路分析:

這一題的思路十分簡單,就是通過Tarjan算法根據強連通分量進行縮點,

然後將所縮的點的所存的金額與是否有酒吧的狀態做出來,

然後用得出來的新圖進行一個SPFA算法的操作得出最大值。

最後的答案是從有酒吧的縮點求最大值。

Tarjan算法求強連通分量參考

代碼實現:

#include<cstdio>
#include<iostream>
#include<queue>
#include<stack>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
int n,m,dfn[500005],low[500005],p1,bel[500005],p2,ans[500005],st,ans1;
struct node{
	int h,z;
}a[500005];
struct nooe{
	int h1,z1;
}di[500005];
vector<int>G[500005];
vector<int>G1[500005];
bool v1[500005];
stack<int>q;
queue<int>s;
void Tarjan(int x)
{
	p1++;
	low[x]=p1;
	dfn[x]=p1;
	q.push(x);
	v1[x]=1;
	for(int i=0;i<G[x].size();i++)
	{
		int v=G[x][i];
		if(!dfn[v])
		{
			Tarjan(v);
			low[x]=min(low[x],low[v]);
		}
		else if(v1[v])
			low[x]=min(low[x],dfn[v]);
	}
	if(low[x]==dfn[x])
	{
		int p;
		p2++;
		do{
			p=q.top();
			q.pop();
			v1[p]=0;
			bel[p]=p2;
		}while(p!=x);
	}
}
void SPFA()
{
	ans[st]=di[st].h1;
	s.push(st);
	memset(v1,0,sizeof(v1));
	v1[st]=1;
	while(!s.empty())
	{
		int t=s.front();
		v1[t]=0;
		s.pop();
		for(int i=0;i<G1[t].size();i++)
		{
			int v=G1[t][i];
			if(ans[v]<ans[t]+di[v].h1)
			{
				ans[v]=ans[t]+di[v].h1;
				if(!v1[v])
				{
					v1[v]=1;
					s.push(v);
				}
			}
		}
	}
}
int read()
{
    int x=0,f=1;
    char s=getchar();
    while(s<'0'||s>'9')
    {
        if(s=='-')
            f=-1;
        s=getchar();
    }
    while(s>='0'&&s<='9')
    {
        x*=10;
        x+=s-'0';
        s=getchar();
    }
    return x*f;
}
int main()
{
	n=read();
	m=read();
	int a1,b;
	for(int i=1;i<=m;i++)
	{
		a1=read();
		b=read();
		G[a1].push_back(b);
	}
	for(int i=1;i<=n;i++)
		a[i].h=read();
	int q,s;
	s=read();
	q=read();
	for(int i=1;i<=q;i++)
	{
		a1=read();
		a[a1].z=1;
	}
	v1[s]=1;
	for(int i=1;i<=n;i++)
        if(!dfn[i])
            Tarjan(i);
	for(int i=1;i<=n;i++)
	{
		di[bel[i]].h1+=a[i].h;
		if(a[i].z==1)
			di[bel[i]].z1=1;
		if(i==s)
			st=bel[i];
		for(int j=0;j<G[i].size();j++)
			if(bel[i]!=bel[G[i][j]])
				G1[bel[i]].push_back(bel[G[i][j]]);
	}
	SPFA();
	for(int i=1;i<=p2;i++)
		if(di[i].z1==1)
			ans1=max(ans1,ans[i]);
	printf("%d",ans1);
}

 

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