HDU3072(Intelligence System)

Intelligence System

Problem Description
After a day, ALPCs finally complete their ultimate intelligence system, the purpose of it is of course for ACM … …
Now, kzc_tc, the head of the Intelligence Department (his code is once 48, but now 0), is sudden obtaining important information from one Intelligence personnel. That relates to the strategic direction and future development of the situation of ALPC. So it need for emergency notification to all Intelligence personnel, he decides to use the intelligence system (kzc_tc inform one, and the one inform other one or more, and so on. Finally the information is known to all).
We know this is a dangerous work. Each transmission of the information can only be made through a fixed approach, from a fixed person to another fixed, and cannot be exchanged, but between two persons may have more than one way for transferring. Each act of the transmission cost Ci (1 <= Ci <= 100000), the total cost of the transmission if inform some ones in our ALPC intelligence agency is their costs sum.
Something good, if two people can inform each other, directly or indirectly through someone else, then they belong to the same branch (kzc_tc is in one branch, too!). This case, it’s very easy to inform each other, so that the cost between persons in the same branch will be ignored. The number of branch in intelligence agency is no more than one hundred.
As a result of the current tensions of ALPC’s funds, kzc_tc now has all relationships in his Intelligence system, and he want to write a program to achieve the minimum cost to ensure that everyone knows this intelligence.
It’s really annoying!

Input
There are several test cases.
In each case, the first line is an Integer N (0< N <= 50000), the number of the intelligence personnel including kzc_tc. Their code is numbered from 0 to N-1. And then M (0<= M <= 100000), the number of the transmission approach.
The next M lines, each line contains three integers, X, Y and C means person X transfer information to person Y cost C.

Output
The minimum total cost for inform everyone.
Believe kzc_tc’s working! There always is a way for him to communicate with all other intelligence personnel.

Sample Input
3 3
0 1 100
1 2 50
0 2 100
3 3
0 1 100
1 2 50
2 1 100
2 2
0 1 50
0 1 100

Sample Output
150
100
50

題意

給定一張有向圖,從0號節點開始發送消息給各個點,如果兩個點之間可以相互到達那麼這兩個點之間的通信費用爲0,問最少需要花費多少錢。

思路

Tarjan + 縮點,最開始我是先縮點,縮完之後對邊排序做kruskal形成一個最小縮點生成樹,好像一看沒啥問題測試數據也過了,但是一直WA。後來發現不對,最小生成樹是針對無向圖的,這個圖是有向圖。
在這裏插入圖片描述
如果是這組測試數據,kruskal + 並查集維護的答案是2,正確答案應該是 101。

最小樹形圖:最小樹形圖就是給有向帶權圖中指定一個特殊的點root,求一棵以root爲根的有向生成樹T,並且T中所有邊的總權值最小。

正確姿勢:Tarjan + 縮點 + 最小樹形圖,還是先縮點,同一個強連通分量中通信費用是0忽略。並且是從0號根節點出發的,找到最小的入邊,最後去縮點邊權值就好。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <cmath>
#include <cstdlib>
#pragma warning(disable:4996)
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 50005;
struct edge{
	int from;
	int to;
	int w;
	int next;
}e[maxn<<1];
stack<int>s;
int head[maxn];			
int dfn[maxn];			
int low[maxn];		
int scc[maxn];			
int sum[maxn];			
int res,cnt,tot;
inline void clear_set()
{
	cnt = tot = res = 0;
	memset(head,-1,sizeof(head));
	memset(dfn,0,sizeof(dfn));
	memset(low,0,sizeof(low));
	memset(scc,0,sizeof(scc));
	memset(sum,0x3f,sizeof(sum));
	while(!s.empty())		s.pop();
}
inline void addedge(int x,int y,int z)
{
	e[tot].from = x;
	e[tot].to = y;
	e[tot].w = z;
	e[tot].next = head[x];
	head[x] = tot++;
}
inline void tarjan(int x)
{
	dfn[x] = low[x] = ++cnt;
	s.push(x);
	for(int i = head[x];~i;i = e[i].next){
		int y = e[i].to;
		if(!dfn[y]){
			tarjan(y);
			low[x] = min(low[x],low[y]);
		}
		else if(!scc[y]){
			low[x] = min(low[x],dfn[y]);
		}
	}
	if(low[x] == dfn[x]){
		res++;
		while(true){
			int t = s.top();
			s.pop();
			scc[t] = res;
			if(t == x)		break;
		}
	}
}
int main()
{
	int n,m;
	while(~scanf("%d%d",&n,&m)){
		clear_set();
		for(int i = 0;i < m;i++){
			int x,y,z;
			scanf("%d%d%d",&x,&y,&z);
			addedge(x,y,z);
		}
		for(int i = 0;i < n;i++){
			if(!dfn[i]){
				tarjan(i);
			}
		}
		for(int i = 0;i < m;i++){			
			int x = e[i].from;
			int y = e[i].to;
			if(scc[x] == scc[y])	continue;				
			if(scc[y] == scc[0])	continue;				
			sum[scc[y]] = min(sum[scc[y]],e[i].w);			//更新最小的兩個縮點之間的邊權值
		}
		int ans = 0;
		for(int i = 1;i <= res;i++){
			if(sum[i] != inf){				
				ans += sum[i];
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}

願你走出半生,歸來仍是少年~

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