对朱刘算法求最小树形图的理解(uva11865)
2017-09-29 21:57
197 查看
题目大意
一个图,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 long const int M=10005,N=65; int T,n,m,c; struct node{int x,y,v,w;}e[M],ee[M]; int pre ,vis ,id ,in ; 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; }
相关文章推荐
- 【有向图的最小树形图---朱刘算法】模板
- POJ 3164 Command Network 朱刘算法求固定根最小树形图
- POJ-3164 Command Network 最小树形图 朱刘算法
- poj3164 (朱刘算法 最小树形图)
- 最小树形图(朱刘算法模板)
- BZOJ 4349: 最小树形图(最小树形图->朱刘算法)
- (最小树形图 朱刘算法) poj 3164
- UVA11865[Stream My Contest] 朱刘算法求最小树形图
- 最小树形图(朱刘算法模板)
- poj 3164 最小树形图模板题目,朱刘算法
- BZOJ 2260: 商店购物/BZOJ 4349: 最小树形图 朱刘算法
- (转)朱刘算法(解决最小树形图问题)的临接表实现
- 朱、刘算法:求最小树形图权值个人理解+个人详解【最小树形图模板】
- (最小树形图 朱刘算法) poj 3164
- POJ-3164 Command Network(最小树形图(有向图的最小生成树)[朱刘算法])
- POJ3164 最小树形图 有向图的最小生成树 模板题 朱刘算法 朱永津-刘振宏算法
- 朱刘算法——最小树形图
- hdu 2121 最小树形图 朱刘算法
- poj 3164 && tju 2248 最小树形图 朱刘算法
- 最小树形图 模版--朱刘算法