C++有向圖的強連通分量—————Summer Holiday

題目描述:

To see a World in a Grain of Sand 
And a Heaven in a Wild Flower, 
Hold Infinity in the palm of your hand 
And Eternity in an hour. 
                  —— William Blake 

聽說lcy幫大家預定了新馬泰7日遊,Wiskey真是高興的夜不能寐啊,他想着得快點把這消息告訴大家,雖然他手上有所有人的聯繫方式,但是一個一個聯繫過去實在太耗時間和電話費了。他知道其他人也有一些別人的聯繫方式,這樣他可以通知其他人,再讓其他人幫忙通知一下別人。你能幫Wiskey計算出至少要通知多少人,至少得花多少電話費就能讓所有人都被通知到嗎? 

輸入:

多組測試數組,以EOF結束。 
第一行兩個整數N和M(1<=N<=1000, 1<=M<=2000),表示人數和聯繫對數。 
接下一行有N個整數,表示Wiskey聯繫第i個人的電話費用。 
接着有M行,每行有兩個整數X,Y,表示X能聯繫到Y,但是不表示Y也能聯繫X。 

輸出:

輸出最小聯繫人數和最小花費。 
每個CASE輸出答案一行。 

輸入樣例:

12 16
2 2 2 2 2 2 2 2 2 2 2 2 
1 3
3 2
2 1
3 4
2 4
3 5
5 4
4 6
6 4
7 4
7 12
7 8
8 7
8 9
10 9
11 10

輸出樣例:

3 6

思路分析:

我們可以這麼想,如果幾個點是一個強連通分量,那麼無論我們從哪裏出發,他們都會被遍歷。

所以通知他們的最小話費爲點集中花費最小的。

之後我們爲了操作簡單,可以將一個強連通分量縮成一個點,點權爲最小花費。

我們將所有的強聯通分量進行如此的操作,則我們就可以得到一個新圖。

那麼,點之間的邊就是原圖中那個強連通分量中的點與不屬於同一分量的點的邊就是現邊。

到了現在,如果點的入度大於0,那麼我們也不需要他的花費,畢竟其他的也可以進入它。

代碼實現:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<stack>
using namespace std;
int n,m,dfn[10005],low[10005],p1,p2,belong[10005],a[10005],ans;
vector<int>G[10005];
bool v1[10005],v[10005];
stack<int>q;
void Tarjan(int u)
{
	p1++;
	low[u]=p1;
	dfn[u]=p1;
	v1[u]=1;
	q.push(u);
	for(int i=0;i<G[u].size();i++)
	{
		int v=G[u][i];
		if(!dfn[v])
		{
			Tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else if(v1[v])
			low[u]=min(low[u],dfn[v]);
	}
	if(low[u]==dfn[u])
	{
		int p;
		p2++;
		do
		{
			p=q.top();
			v1[p]=0;
			belong[p]=p2;
			q.pop();
		}while(p!=u);
	}
}
int main()
{
	while(scanf("%d%d",&n,&m)!=-1&&(n||m))
	{
		memset(dfn,0,sizeof(dfn));
		memset(v1,0,sizeof(v1));
		memset(v,0,sizeof(v));
		memset(low,0,sizeof(low));
		int a1,b;
		p1=0;
		p2=0;
		for(int i=1;i<=n;i++)
            G[i].clear();
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
		for(int i=1;i<=m;i++)
		{
			scanf("%d%d",&a1,&b);
			G[a1].push_back(b);
		}
		for(int i=1;i<=n;i++)
        {
            if(!dfn[i])
                Tarjan(i);
        }
        ans=0;
        for(int i=1;i<=n;i++)
        	for(int j=0;j<G[i].size();j++)
        	{
        		if(belong[i]!=belong[G[i][j]])
        			v[belong[G[i][j]]]=1;
			}
		int num=0;
		for(int i=1;i<=p2;i++)
		{
			if(v[i])
				continue;
			num++;
			int minn=0x3f3f3f3f;
			for(int j=1;j<=n;j++)
				if(belong[j]==i)
					minn=min(minn,a[j]);
			ans+=minn;
		}
		printf("%d %d\n",num,ans);
	}
	return 0;
}

 

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