hdu3072 强连通+最小树形图
2015-09-15 18:56
423 查看
题意:有一个人他要把一个消息通知到所有人,已知一些通知关系:A 能通知 B,需要花费 v,而又知道,如果某一个小团体,其中的成员相互都能直接或间接通知到,那么他们之间的消息传递是不需要花费的,现在问这个人将消息传给所有人所需的最小花费。
首先,一个团体中能够相互通知其实就是一个强连通分量,所以首先找出所有强连通分量,因为内部不需要花费,所以他们就相当于一个点,而早缩点之后,我们就得到了一张有向无环图,消息传递的最小花费其实就是最小树形图的边权和。刚做这个题的时候我还只是看见过最小树形图是什么,做到了我就自己YY了一种做法,就是从每个点拓展,用优先队列存可以拓展的边,取最小边看能否合并还不在树上的点,合并一个点就把它的所有出边再入优先队列。后来WA了我自己也举出反例,就去学习了一下最小树形图的朱刘算法,然后A掉了。
View Code
首先,一个团体中能够相互通知其实就是一个强连通分量,所以首先找出所有强连通分量,因为内部不需要花费,所以他们就相当于一个点,而早缩点之后,我们就得到了一张有向无环图,消息传递的最小花费其实就是最小树形图的边权和。刚做这个题的时候我还只是看见过最小树形图是什么,做到了我就自己YY了一种做法,就是从每个点拓展,用优先队列存可以拓展的边,取最小边看能否合并还不在树上的点,合并一个点就把它的所有出边再入优先队列。后来WA了我自己也举出反例,就去学习了一下最小树形图的朱刘算法,然后A掉了。
#include<stdio.h> #include<string.h> #include<stack> #include<queue> #include<algorithm> using namespace std; typedef long long ll; const int maxn=5e4+5; const int maxm=1e5+5; const int INF=0x3f3f3f3f; int head[maxn],point[maxm],nxt[maxm],size,val[maxm]; int n,t,scccnt; int stx[maxn],low[maxn],scc[maxn],vis[maxn]; int from[maxm],to[maxm],cost[maxm],cntm; int pre[maxn],id[maxn],in[maxn]; stack<int>S; void init(){ memset(head,-1,sizeof(head)); size=cntm=0; memset(vis,0,sizeof(vis)); } void add_mdst(int a,int b,int v){ from[cntm]=a; to[cntm]=b; cost[cntm++]=v; } ll mdst(int s,int n){ ll ans=0; int u,v; while(1){ memset(in,0x3f,sizeof(in)); for(int i=0;i<cntm;++i){ if(from[i]!=to[i]&&cost[i]<in[to[i]]){ pre[to[i]]=from[i]; in[to[i]]=cost[i]; } } for(int i=1;i<=n;++i){ if(i!=s&&in[i]==INF){ return -1; } } int cnt=0; memset(id,-1,sizeof(id)); memset(vis,-1,sizeof(vis)); in[s]=0; for(int i=1;i<=n;++i){ ans+=in[i]; v=i; while(vis[v]!=i&&id[v]==-1&&v!=s){ vis[v]=i; v=pre[v]; } if(v!=s&&id[v]==-1){ ++cnt; for(u=pre[v];u!=v;u=pre[u])id[u]=cnt; id[v]=cnt; } } if(!cnt)break; for(int i=1;i<=n;++i){ if(id[i]==-1)id[i]=++cnt; } for(int i=0;i<cntm;){ v=to[i]; from[i]=id[from[i]]; to[i]=id[to[i]]; if(from[i]!=to[i])cost[i++]-=in[v]; else{ --cntm; cost[i]=cost[cntm]; to[i]=to[cntm]; from[i]=from[cntm]; } } n=cnt; s=id[s]; } return ans; } void add(int a,int b,int v){ point[size]=b; val[size]=v; nxt[size]=head[a]; head[a]=size++; } void dfs(int s){ stx[s]=low[s]=++t; S.push(s); for(int i=head[s];~i;i=nxt[i]){ int j=point[i]; if(!stx[j]){ dfs(j); low[s]=min(low[s],low[j]); } else if(!scc[j]){ low[s]=min(low[s],stx[j]); } } if(low[s]==stx[s]){ scccnt++; while(1){ int u=S.top();S.pop(); scc[u]=scccnt; if(s==u)break; } } } void setscc(){ memset(stx,0,sizeof(stx)); memset(scc,0,sizeof(scc)); t=scccnt=0; for(int i=1;i<=n;++i)if(!stx[i])dfs(i); for(int i=1;i<=n;++i){ for(int j=head[i];~j;j=nxt[j]){ int k=point[j]; if(scc[i]!=scc[k]){ add_mdst(scc[i],scc[k],val[j]); } } } } int main(){ int m; while(scanf("%d%d",&n,&m)!=EOF){ init(); while(m--){ int a,b,v; scanf("%d%d%d",&a,&b,&v); add(a+1,b+1,v); } setscc(); ll ans=0; int pre=scc[1]; printf("%I64d\n",mdst(pre,scccnt)); } return 0; }
View Code
相关文章推荐
- rails网站分享到朋友圈功能是怎么实现的
- 使用Uncrustify在Xcode中格式化Objective-C代码
- SpringMvc[学习手记]-框架搭建
- 学习笔记--进程及线程间通信方式的区别及联系
- QQ中未读气泡拖拽消失的实现分析
- android应用使用ant打包过程
- Android开发入门(初学)
- linux 查找文件或目录
- Java中堆内存与栈内存分配浅析
- Qt 学习之路:输入元素
- 判断iOS设备型号
- string object to oracle check
- Python学习笔记 -- 第一章
- Redis的图形界面管理工具phpRedisAdmin
- IDisposable接口
- Android的Handler总结
- 14级组队赛第一场3319 A simple water problem
- POJ - 1308 Is It A Tree?(并查集+dfs)
- 最近总结关于找iOS的工作的体会,大家可以补充
- .NET跨平台之旅:将示例站点从ASP.NET 5 Beta5升级至Beta7