题意:有一个人他要把一个消息通知到所有人,已知一些通知关系: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 }
时间: 2024-10-15 14:15:58