hdu3072 强连通+最小树形图

题意:有一个人他要把一个消息通知到所有人,已知一些通知关系: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

hdu3072 强连通+最小树形图的相关文章

HDU 3072 Intelligence System(强连通+最小树形图)

HDU 3072 Intelligence System 题目链接 题意:给定有向图,边有权值,求保留一些边,从一点出发,能传递到其他所有点的最小代价,保证有解 思路:先缩点,然后从入度为0的点作为起点(因为题目保证有解,所以必然有一个且只有一个入度为0的点),然后做一下最小树形图即可 代码: #include <cstdio> #include <cstring> #include <vector> #include <algorithm> #includ

[tarjan+最小树形图] hdu 3072 Intelligence System

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3072 Intelligence System Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1479    Accepted Submission(s): 653 Problem Description After a day, ALP

bzoj4349: 最小树形图

最小树形图模板题…… 这种\(O(nm)\)的东西真的能考到么…… #include <bits/stdc++.h> #define N 60 #define INF 1000000000 using namespace std; int n, m, nn; double ai[N], an[N], ci[2][N][N], ans; int bc[N]; int ini[N], vis[N], inc[N], inl[N]; int dfn; int dfs(int t) { vis[t]

Directed_MST 最小树形图

List Directed_MST 最小树形图 List Knowledge 模板 Practice 参考资料 Knowledge 求一个图中遍历到每个点的方案中的最小边权和,显然n-1条边,即一颗树即可. 最小生成树?当然这里不是的,这里的最小树形图算法是针对有向图的. 最小树形图的第一个算法是1965年朱永津和刘振宏提出的复杂度为O(VE)的算法.简称朱刘算法. 1986年, Gabow, Galil, Spencer和Tarjan提出了一个复杂度更好的实现,其时间复杂度为O(E+VlogV

hdu2121+不定根最小树形图

算和定根最小树形图相同. 我们只需:设一个权值sumw=所有边之和+1,类似于网络流,向图中加入一个超级源点,把这个点作为虚根.虚根到其他所有点之间连上一条边,边权值为sumw. 求出的值减去sumw即为最小树形图的权值. 当然,返回-1则无解.此外,当求出的值>=2*sumw,也是无解的. 1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 struct node 5 { 6 int u,v; 7

HDOJ 2121 Ice_cream’s world II 最小树形图无根树

朱刘算法 最小树形图无根树: 建立一个虚拟的根节点,向所有节点连边,权值为其他所有边的权值和+1 在求最小树形图的时候,记录和虚拟的根相连的是哪个节点 在这题中,边是从小往大加的所以直接记录的是相连的是第几号边.... Ice_cream's world II Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3442    Accept

最小树形图【模板】

基于贪心和缩点的思想. 假设根的顶点是V0. (1)除了根结点外,所有的点Vi,找到以Vi为终点的最短的边,加入集合中 (pre[v]存放的是终点v的起点,In[v]存放终点为v的最短的边) (2)检查集合中有没有有向环和收缩点.若没有有向环和收缩点,结束计算:若没有有向环.但含收缩边,则跳至步骤(4):若含有有向环,则跳至步骤(3).Ps:如果出现重边,将忽略权值较高的 (3)含有有向环,则收缩有向环(缩点),把有向环收缩为一个点,其有向环内的边被收缩掉,而环外的边被保 留,构建新图,重复步骤

HDU 2121 Ice_cream’s world II (不定根最小树形图)

题目地址:HDU 2121 这题没有给定根.最容易想到的当然是暴力,枚举所有的根,但是TLE是显然的..为了处理不定根的情况,可以虚拟一个根,然后用这个根去跟所有的点连边,权值为其他所有权值的和+1,目的是防止成为最小树形图的一条边.然后跑出最小树形图后,那么这个虚拟根肯定跟一个实际根相连,这时候根就找到了,然后再在最终的总花费中减去虚拟的那条边的权值就可以了. 代码如下: #include <iostream> #include <string.h> #include <m

HDU2121 Ice_cream’s world II【最小树形图】【不定根】

Ice_cream's world II Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3005    Accepted Submission(s): 704 Problem Description After awarded lands to ACMers, the queen want to choose a city be he