对朱刘算法求最小树形图的理解(uva11865)
来源:互联网 发布:mac 双定制粉底液 肤质 编辑:程序博客网 时间:2024/06/07 02:06
题目大意
一个图,0号节点是源点,每一条单向边有一个价值v和一个费用w,你只有C元钱,要使得源点和所有点都连通,且价值最小的边的价值最大。
题目分析
二分最小价值,只有比最小价值大的价值的边才能够加进去+最小树形图
最小树形图是什么呢?除了根节点以外,每一个点都有一个入度,且根节点可以到达所有节点的神奇图叫做树形图,而最小树形图,当然就是边权和最小咯!。
朱刘算法
步骤1
操作内容:贪心,给除了根节点以外的每一个点都找一个前驱节点,其中前驱节点到该节点的边是尽可能小的。如果某一个点没有入度,那么肯定就不存在树形图咯!
for(i=1;i<=m;++i){ if(e[i].v>=lim&&e[i].x!=e[i].y&&e[i].w<in[e[i].y]) in[e[i].y]=e[i].w,pre[e[i].y]=e[i].x; } for(i=1;i<=num;++i)if(!pre[i]&&i!=rt)return 0; in[rt]=0,js=0;
步骤2
寻找简单环,因为我们已经找出前驱节点了,所以我们顺着前驱节点找简单环就可以了。如果没有简单环,那么就皆大欢喜,找到解了。如果有简单环呢?我们的目标是拆掉这个环中的一条边,然后连另一条入边进入这个点。这个方法可以用贪心的思想感受一下……
然后给每个简单环标号,以后它们是要被缩成一个点的。
for(i=1;i<=num;++i){ re+=in[i],t1=i;//re+=in[i]:这个计算答案的方法在步骤3有讲解 while(t1!=rt&&vis[t1]!=i&&!id[t1])vis[t1]=i,t1=pre[t1]; if(t1!=rt&&!id[t1]){//在t1处找到了简单环 t2=pre[t1],++js; while(t2!=t1)id[t2]=js,t2=pre[t2]; id[t1]=js;//标号 } } if(!js){return re<=c;}//没有简单环,即找到结论 for(i=1;i<=num;++i)if(!id[i])id[i]=++js;
步骤3
缩点。
所有简单环看作一个点x,然后对于从环里走出的出边,就是x向外的出边,不用改变边权。对于入边,如果环外一点y到环内一点z之间有一条边权为w1的边,而如上面代码,in[y]=w2,则新边改成y到x的边,边权为w1-w2
为什么这么搞事呢?因为大家肯定注意到上面代码有这么一句:
re+=in[i];
所以说,我们这样只是减去原来选择的边造成的贡献,加上新边造成的贡献而已。
为了方便理解,给图如下:
for(i=1;i<=m;++i)if(e[i].v>=lim){ int kl=e[i].y;e[i].x=id[e[i].x],e[i].y=id[e[i].y]; if(e[i].x!=e[i].y)e[i].w-=in[kl]; } rt=id[rt],num=js;
分段的代码可能有一些变量名没有解释清楚,那么看完整版代码吧。
代码
#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<climits>#include<cmath>using namespace std;#define LL long longconst int M=10005,N=65;int T,n,m,c;struct node{int x,y,v,w;}e[M],ee[M];int pre[N],vis[N],id[N],in[N];int ok(int lim){ int re=0,i,j,num=n,rt=1,js,t1,t2; for(i=1;i<=m;++i)e[i]=ee[i]; while(1){ for(i=1;i<=num;++i)pre[i]=id[i]=vis[i]=0,in[i]=1e9; for(i=1;i<=m;++i){ if(e[i].v>=lim&&e[i].x!=e[i].y&&e[i].w<in[e[i].y])//e[i].x!=e[i].y别忘了 in[e[i].y]=e[i].w,pre[e[i].y]=e[i].x; } for(i=1;i<=num;++i)if(!pre[i]&&i!=rt)return 0; in[rt]=0,js=0;//步骤1 for(i=1;i<=num;++i){ re+=in[i],t1=i; while(t1!=rt&&vis[t1]!=i&&!id[t1])vis[t1]=i,t1=pre[t1]; if(t1!=rt&&!id[t1]){//t1! t2=pre[t1],++js; while(t2!=t1)id[t2]=js,t2=pre[t2]; id[t1]=js; } } if(!js){return re<=c;} for(i=1;i<=num;++i)if(!id[i])id[i]=++js;//步骤2 for(i=1;i<=m;++i)if(e[i].v>=lim){//别忘了这句 int kl=e[i].y;e[i].x=id[e[i].x],e[i].y=id[e[i].y]; if(e[i].x!=e[i].y)e[i].w-=in[kl]; } rt=id[rt],num=js;//步骤3 }}int main(){ int i,j,l,r,mid,ans; scanf("%d",&T); while(T--){ scanf("%d%d%d",&n,&m,&c); l=0,r=0,ans=-1; for(i=1;i<=m;++i){ scanf("%d%d%d%d",&ee[i].x,&ee[i].y,&ee[i].v,&ee[i].w); ++ee[i].x,++ee[i].y;r=max(r,ee[i].v); } while(l<=r){//二分答案 mid=(l+r)>>1; if(ok(mid))ans=mid,l=mid+1; else r=mid-1; } if(ans==-1)printf("streaming not possible.\n"); else printf("%d kbps\n",ans); } return 0;}
阅读全文
0 0
- 对朱刘算法求最小树形图的理解(uva11865)
- UVA11865[Stream My Contest] 朱刘算法求最小树形图
- 最小树形图uva11865
- 朱、刘算法:求最小树形图权值个人理解+个人详解【最小树形图模板】
- 朱、刘算法:求最小树形图权值个人理解+个人详解【最小树形图模板】
- 求最小树形图的朱刘算法
- poj 3164 <朱刘算法《模板》求最小树形图>
- uva11865 - Stream My Contest 最小树形图+二分
- 最小树形图(刘朱算法)
- 最小树形图(朱-刘算法)
- 最小树形图(朱-刘算法)
- 最小树形图(朱-刘算法)
- 最小树形图(朱-刘算法)
- 最小树形图(有向图的最小生成树)朱刘算法
- 我对Prim算法用于求无向图的最小生成树的理解 (C++实现)
- bzoj4349&2260 最小树形图(商店购物)(朱刘算法 最小树形图)
- BZOJ 4349: 最小树形图(最小树形图->朱刘算法)
- 最小树形图 模版--朱刘算法
- Unicode和UTF-8有何区别?
- JAVA内部类2
- 去除数据库数据表中重复的记录的sql语句
- 关于CSS的一些基础内容
- markdown 的简单使用
- 对朱刘算法求最小树形图的理解(uva11865)
- JZOJ 5267. 费马点问题
- bzoj 4530(DFS序+线段树合并)
- 9.28-9.29 课程记录
- 小薇学院任务一:零基础HTML编码(笔记)
- bzoj 1966: [Ahoi2005]VIRUS 病毒检测
- Python学习笔记:高阶函数(函数指针)与装饰器
- MySQL之DML语句(上)
- 梯度下降法的三种形式BGD、SGD以及MBGD