UVA 11865 Stream My Contest
来源:互联网 发布:学霸有多努力知乎 编辑:程序博客网 时间:2024/05/17 01:57
题意:需要用不超过cost元来建立一个能到所有点的网络,每条边都有花费和带宽,要求一颗能到所有点的树,使得整棵树的最小带宽(即该图中所有点的带宽的最小值)最大。
解析:如果已知最小带宽了,问题转化为:如果仅用小于此带宽的网线,是否可以再给定花费内成功搭建网络,则明显应该求最小生成树,因为是有向图,所以就是最小树形图,可以用朱刘算法来求。朱刘算法详解:http://blog.sina.com.cn/s/blog_6af663940100ls4h.html
我的代码里注释还是挺详细的,如果还有不懂得话,大家可以自己画个图模拟一下过程就行了
然后可以二分最小带宽,删去图中比最小带宽的带宽还小的边。
当最小带宽越小,删除的边就越少,就越容易构成最小树形图。因为要求最小带宽的最大值,所以就可以二分这个最小带宽
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;#define MEM(x,y) memset(x,y,sizeof(x))#define Pmax 100#define Emax 11000#define Max 1000000000struct edge{int from,to;int len;//长度int band;//带宽}e[5*Emax];int pre[Pmax],vis[Pmax];//pre[]用来存点的前驱点,vis[]用来记录在最小树形图中该点是由那个点遍历得到的int id[Pmax];//id[]用来存缩环之后点合并的坐标int in[Pmax];//in[]存进入该点的最短入边int N,M,C;int cnt;void addedge(int a,int b,int c,int d)//x代表从哪开始存{e[cnt].band = c;e[cnt].from = a;e[cnt].to = b;e[cnt].len = d;e[cnt+M].band = c;//因为每一次在Directed_MST里都会改变e[],所以把最初的存在M->2*M-1里e[cnt+M].from = a;e[cnt+M].to = b;e[cnt+M].len = d;cnt++;}bool Directed_MST(int root ,int Band,int n)//Band是这次所求的最小带宽,n是点的个数{long long ans = 0;while(1){//求每个点的最小入边MEM(pre,-1);for(int i = 0 ; i < n ; i ++)in[i] = Max;for(int i = 0 ; i < M; i++){int from = e[i].from;int to = e[i].to;if(from != to && e[i].band >= Band && e[i].len < in[to])//3个条件:没有自环;大于最小带宽;求in[i]最小值{in[to] = e[i].len;pre[to] = from;}}//判断有没有为树for(int i = 0 ; i < n;i++){if(i == root)continue;if(in[i]==Max)//代表有的点没到,即不可能是最小树形图了return false;}//找到环int subnode = 0;//用来记录缩环后的环的替代点MEM(vis,-1);MEM(id,-1);in[root] = 0;//根节点没有入边,所以边权为0for(int i = 0 ; i < n;i++){ans += in[i];//注意此时加上所有的点的入边权值,在后面有相应的对应int temp = i;while(vis[temp] != i && id[temp] == -1 && temp != root){vis[temp] = i;//temp由i点遍历得到temp = pre[temp];}//i点向父节点遍历如果有环的话,temp肯定是环中的某个点,不一定是i点if(temp != root && id[temp] == -1){int u = pre[temp];for( ;u != temp; u = pre[u])id[u] = subnode;//同一个环中的所有点都是用这个替代点表示id[temp] = subnode;subnode++;}}if(subnode == 0)//代表没有环了,也就是说现在已经是最小树形图了break;for(int i = 0 ; i < n; i ++)if(id[i] == -1)//对于不在环中的点,也给他们重新找替代点id[i] = subnode++;//缩环,重新标记for(int i = 0 ; i < M ; i ++){int temp = e[i].to;e[i].from = id[e[i].from];//全部更新为新的替代点e[i].to = id[e[i].to];if(e[i].from != e[i].to)//如果不是在同一个环内的话,就要减少边长e[i].len -= in[temp];//对于指向环的边,这么减没问题;对于从环内点指向外面的边//之所以这么减,是因为上面ans已经把所有点的入点边权都加上了,对应上面//也就是说如果ans表示的仅仅是环内的边权话,那么就只是入边减,出边不减了}root = id[root];//最后更新根节点和点的个数n = subnode;}if(ans <= C)return true;elsereturn false;}int main(){int T;scanf("%d",&T);while(T--){scanf("%d%d%d",&N,&M,&C);int maxb = 0,minb = Max;//用来存最大最小带宽,后面二分用cnt = 0;for(int i = 1; i <= M ; i ++){int a,b,c,d;scanf("%d%d%d%d",&a,&b,&c,&d);addedge(a,b,c,d);maxb = max(maxb,c);minb = min(minb,c);}if(Directed_MST(0,minb,N) == false)//如果最小带宽取最小值时(即图中的每条边都没删)都不能构成最小树形图printf("streaming not possible.\n");else{int l = minb,r = maxb;int mid;while(l<r)//二分过程{mid = l+(r-l+1)/2;for(int i = 0 ; i < M; i ++)e[i] = e[i+M];if(Directed_MST(0,mid,N) == true)//如果最小带宽满足,就可以取更大的带宽l = mid;elser = mid-1;}printf("%d kbps\n",r);}}return 0;}
- UVA 11865 Stream My Contest
- UVA-11865 - Stream My Contest(最小树形图)
- uva 11865 stream my contest
- uva 11865 stream my contest
- UVa 11865 Stream My Contest 二分+最小树形图
- UVA 11865 - Stream My Contest(最小树形图)
- UVA 11865 Stream My Contest (最小树形图 + 二分)
- UVA - 11865 Stream My Contest(朱刘算法)
- [UVA 11865]Stream My Contest[最小树形图][二分答案]
- UVA 11865 Stream My Contest(最小树形图+二分)
- UVA 11865 Stream My Contest 二分枚举 + 最小树形图
- UVA 11865 Stream My Contest(最小树形图+二分)
- UVA 11865 Stream My Contest(最小树形图,4级)
- UVA 11865 Stream My Contest(最小树形图、朱刘算法)
- uva 11865 - Stream My Contest(二分+有向最小生成树)
- uva11865 - Stream My Contest
- lightoj 1384 Stream My Contest
- uva11865 - Stream My Contest 最小树形图+二分
- UVA 10252 (13.07.13)
- 创建一个基于Struts2的Web应用
- eclipse-myeclise 自定义注释中的变量名称
- PHP XCache缓存安装使用
- Matrix Operation解题报告
- UVA 11865 Stream My Contest
- POJ 2479 Maximum sum (同POJ 2593 Max Sequence)
- org.hibernate.LazyInitializationException的解决方法
- hdu3790 (最短路)
- Cocos2d-x中拖动滑块的控件类CCControlSlider使用
- 开始试着写博客
- 传智播客Java自学笔记第11天(待编辑)
- gcc 和 g++ 的区别
- 关于f200,摄影和发帖的点点滴滴