题意:有一个人他要把一个消息通知到所有人,已知一些通知关系:A 能通知 B,需要花费 v,而又知道,如果某一个小团体,其中的成员相互都能直接或间接通知到,那么他们之间的消息传递是不需要花费的,现在问这个人将消息传给所有人所需的最小花费。
首先,一个团体中能够相互通知其实就是一个强连通分量,所以首先找出所有强连通分量,因为内部不需要花费,所以他们就相当于一个点,而早缩点之后,我们就得到了一张有向无环图,消息传递的最小花费其实就是最小树形图的边权和。刚做这个题的时候我还只是看见过最小树形图是什么,做到了我就自己YY了一种做法,就是从每个点拓展,用优先队列存可以拓展的边,取最小边看能否合并还不在树上的点,合并一个点就把它的所有出边再入优先队列。后来WA了我自己也举出反例,就去学习了一下最小树形图的朱刘算法,然后A掉了。
1 #include<stdio.h>
2 #include<string.h>
3 #include<stack>
4 #include<queue>
5 #include<algorithm>
6 using namespace std;
7 typedef long long ll;
8
9 const int maxn=5e4+5;
10 const int maxm=1e5+5;
11 const int INF=0x3f3f3f3f;
12
13 int head[maxn],point[maxm],nxt[maxm],size,val[maxm];
14 int n,t,scccnt;
15 int stx[maxn],low[maxn],scc[maxn],vis[maxn];
16 int from[maxm],to[maxm],cost[maxm],cntm;
17 int pre[maxn],id[maxn],in[maxn];
18 stack<int>S;
19
20 void init(){
21 memset(head,-1,sizeof(head));
22 size=cntm=0;
23 memset(vis,0,sizeof(vis));
24 }
25
26 void add_mdst(int a,int b,int v){
27 from[cntm]=a;
28 to[cntm]=b;
29 cost[cntm++]=v;
30 }
31
32 ll mdst(int s,int n){
33 ll ans=0;
34 int u,v;
35 while(1){
36 memset(in,0x3f,sizeof(in));
37 for(int i=0;i<cntm;++i){
38 if(from[i]!=to[i]&&cost[i]<in[to[i]]){
39 pre[to[i]]=from[i];
40 in[to[i]]=cost[i];
41 }
42 }
43 for(int i=1;i<=n;++i){
44 if(i!=s&&in[i]==INF){
45 return -1;
46 }
47 }
48 int cnt=0;
49 memset(id,-1,sizeof(id));
50 memset(vis,-1,sizeof(vis));
51 in[s]=0;
52 for(int i=1;i<=n;++i){
53 ans+=in[i];
54 v=i;
55 while(vis[v]!=i&&id[v]==-1&&v!=s){
56 vis[v]=i;
57 v=pre[v];
58 }
59 if(v!=s&&id[v]==-1){
60 ++cnt;
61 for(u=pre[v];u!=v;u=pre[u])id[u]=cnt;
62 id[v]=cnt;
63 }
64 }
65 if(!cnt)break;
66 for(int i=1;i<=n;++i){
67 if(id[i]==-1)id[i]=++cnt;
68 }
69 for(int i=0;i<cntm;){
70 v=to[i];
71 from[i]=id[from[i]];
72 to[i]=id[to[i]];
73 if(from[i]!=to[i])cost[i++]-=in[v];
74 else{
75 --cntm;
76 cost[i]=cost[cntm];
77 to[i]=to[cntm];
78 from[i]=from[cntm];
79 }
80 }
81 n=cnt;
82 s=id[s];
83 }
84 return ans;
85 }
86
87 void add(int a,int b,int v){
88 point[size]=b;
89 val[size]=v;
90 nxt[size]=head[a];
91 head[a]=size++;
92 }
93
94 void dfs(int s){
95 stx[s]=low[s]=++t;
96 S.push(s);
97 for(int i=head[s];~i;i=nxt[i]){
98 int j=point[i];
99 if(!stx[j]){
100 dfs(j);
101 low[s]=min(low[s],low[j]);
102 }
103 else if(!scc[j]){
104 low[s]=min(low[s],stx[j]);
105 }
106 }
107 if(low[s]==stx[s]){
108 scccnt++;
109 while(1){
110 int u=S.top();S.pop();
111 scc[u]=scccnt;
112 if(s==u)break;
113 }
114 }
115 }
116
117 void setscc(){
118 memset(stx,0,sizeof(stx));
119 memset(scc,0,sizeof(scc));
120 t=scccnt=0;
121 for(int i=1;i<=n;++i)if(!stx[i])dfs(i);
122 for(int i=1;i<=n;++i){
123 for(int j=head[i];~j;j=nxt[j]){
124 int k=point[j];
125 if(scc[i]!=scc[k]){
126 add_mdst(scc[i],scc[k],val[j]);
127 }
128 }
129 }
130 }
131
132 int main(){
133 int m;
134 while(scanf("%d%d",&n,&m)!=EOF){
135 init();
136 while(m--){
137 int a,b,v;
138 scanf("%d%d%d",&a,&b,&v);
139 add(a+1,b+1,v);
140 }
141 setscc();
142 ll ans=0;
143 int pre=scc[1];
144 printf("%I64d\n",mdst(pre,scccnt));
145 }
146 return 0;
147 }