hdu 3072
强连通分量——tarjin 算法
这道题和前面那道hdu 2767唯一不同就是,2767需要找出最小数量的边使图成为连通分量,而这个题需要一点点贪心的思想在里面,它需要求出代价最小的边使图成为连通分量;
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <stack> 5 #define N 50006 6 using namespace std; 7 8 struct Edge 9 { 10 int u, val, next; 11 Edge() {} 12 Edge(int a, int b, int c) 13 { 14 u=a, val=b, next=c; 15 } 16 } edge[100006]; 17 18 int head[N],tot,n,m,dfn[N],low[N],T,ind,id[N],in[N]; 19 bool vs[N]; 20 stack<int> S; 21 22 void add_edge(int st, int en, int val) 23 { 24 edge[tot]=Edge(en,val,head[st]); 25 head[st]=tot++; 26 } 27 28 void tarjan(int u) 29 { 30 S.push(u), vs[u]=true; 31 dfn[u]=low[u]=T++; 32 for(int e=head[u]; e!=-1; e=edge[e].next) 33 { 34 int v=edge[e].u; 35 if(!dfn[v]) 36 { 37 tarjan(v); 38 low[u]=min(low[u], low[v]); 39 } 40 else if(vs[v] && low[u]>dfn[v]) low[u]=dfn[v]; 41 } 42 if(low[u]==dfn[u]) 43 { 44 ind++; 45 int v; 46 do 47 { 48 v=S.top(); 49 S.pop(); 50 id[v]=ind; 51 vs[v]=false; 52 }while(v!=u); 53 } 54 } 55 56 int main() 57 { 58 while(scanf("%d%d", &n, &m)!=EOF) 59 { 60 memset(head, -1, sizeof head); 61 tot=0; 62 for(int i=0, a, b, c; i<m; i++) 63 { 64 scanf("%d%d%d", &a, &b, &c); 65 add_edge(a,b,c); 66 } 67 while(!S.empty()) S.pop(); 68 memset(vs, 0, sizeof vs); 69 memset(dfn,0, sizeof dfn); 70 memset(low,0,sizeof low); 71 T=ind=0; 72 for(int i=0; i<n; i++) if(!dfn[i]) tarjan(i); 73 for(int i=0; i<ind; i++) in[i]=999999; 74 for(int i=0; i<n; i++) 75 { 76 int u=id[i]; 77 for(int e=head[i]; e!=-1; e=edge[e].next) 78 { 79 int v=id[edge[e].u]; 80 if(u!=v) in[v]=min(in[v], edge[e].val); 81 } 82 } 83 int ans=0; 84 for(int i=0; i<ind; i++) 85 { 86 if(i==id[0]||in[i]==999999) continue; 87 ans+=in[i]; 88 } 89 printf("%d\n", ans); 90 } 91 return 0; 92 }