题目大意
给了一个含有 n(0<n<=50000) 个节点的有向图,图中的两点之间的通信时要付出代价的(经过的边权之和),但是如果这两个点之间相互可达,代价为 0
问,从给定的节点向其他所有的点通信,所花费的最小代价是多少?
做法分析
先对原图缩点,形成一个 DAG,给的那个定点显然是 DAG 中入度为 0 的点,并且入度为 0 的点肯定只有一个(根据题目的意思)
每个顶点(除了那个定点)必定只有一个入点,那么,对于每个顶点,完全可以选择代价最小的那条入点,贪心的找即可
参考代码

1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <stack> 5 6 using namespace std; 7 8 const int N=50006; 9 10 struct Edge 11 { 12 int u, val, next; 13 Edge() {} 14 Edge(int a, int b, int c) 15 { 16 u=a, val=b, next=c; 17 } 18 } edge[100006]; 19 int head[N], tot; 20 int n, m; 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 int dfn[N], low[N], T, ind, id[N]; 29 bool vs[N]; 30 stack<int> S; 31 32 void tarjan(int u) 33 { 34 S.push(u), vs[u]=true; 35 dfn[u]=low[u]=T++; 36 for(int e=head[u]; e!=-1; e=edge[e].next) 37 { 38 int v=edge[e].u; 39 if(dfn[v]==-1) 40 { 41 tarjan(v); 42 low[u]=min(low[u], low[v]); 43 } 44 else if(vs[v] && low[u]>dfn[v]) low[u]=dfn[v]; 45 } 46 if(low[u]==dfn[u]) 47 { 48 for(int v; 1; ) 49 { 50 v=S.top(); 51 id[v]=ind; 52 vs[v]=false, S.pop(); 53 if(v==u) break; 54 } 55 ind++; 56 } 57 } 58 59 int in[N]; 60 61 int main() 62 { 63 while(scanf("%d%d", &n, &m)!=EOF) 64 { 65 memset(head, -1, sizeof head); 66 tot=0; 67 for(int i=0, a, b, c; i<m; i++) 68 { 69 scanf("%d%d%d", &a, &b, &c); 70 add_edge(a, b, c); 71 } 72 while(!S.empty()) S.pop(); 73 memset(vs, 0, sizeof vs); 74 memset(dfn, -1, sizeof dfn); 75 T=ind=0; 76 for(int i=0; i<n; i++) if(dfn[i]==-1) tarjan(i); 77 for(int i=0; i<ind; i++) in[i]=0x3fffffff; 78 for(int i=0; i<n; i++) 79 { 80 int u=id[i]; 81 for(int e=head[i]; e!=-1; e=edge[e].next) 82 { 83 int v=id[edge[e].u]; 84 if(u!=v) in[v]=min(in[v], edge[e].val); 85 } 86 } 87 int ans=0; 88 for(int i=0; i<ind; i++) 89 { 90 if(i==id[0]) continue; 91 ans+=in[i]; 92 } 93 printf("%d\n", ans); 94 } 95 return 0; 96 }