• [最小割][Kruskal] Luogu P5039 最小生成树


    题目描述

    Secsa最近对最小生成树问题特别感兴趣。他已经知道如果要去求出一个 nn 个点、 mm 条边的无向图的最小生成树有一个Krustal算法和另一个Prim的算法。另外,他还知道,某一个图可能有多种不同的最小生成树。例如,下面图3中所示的都是图2中的无向图的最小生成树:

    当然啦,这些都不是今天需要你解决的问题。Secsa想知道对于某一条无向图中的边AB,至少需要多少代价可以保证AB边在这个无向图的最小生成树中。为了使得AB边一定在最小生成树中,你可以对这个无向图进行操作,一次单独的操作是指:先选择一条图中的边 P1P2,再把图中除了这条边以外的边,每一条的权值都减少 11 。如图4所示就是一次这样的操作:

    题解

    • 我们可以发现让其余所有边都减1和让自己加1没什么区别

    • 考虑kruskal的过程,首先边权大于这条边的是不用考虑的

    • 考虑把那些边权比这条边小的调节到比这条边大,这样就相当于在生成树上去掉了这条边

    • 至于调大到多少自然是使得边权恰好大1

    • 让这条边必然存在就一定得让这条边链接的两个点不连通,于是我们把在生成树上去掉这条边看成割断这条边,于是这就是一个最小割

    代码

     1 #include <queue>
     2 #include <cstdio>
     3 #include <iostream>
     4 #include <algorithm>
     5 using namespace std;
     6 const int N=1010;
     7 queue<int> Q;
     8 struct edge{int to,from,w;}e[N*4];
     9 struct node{int u,v,w,o;}E[N];
    10 int n,m,S,T,k,t,cnt=1,ans,head[N],d[N],cur[N];
    11 int cmp(node a,node b) { return a.w==b.w?a.o<b.o:a.w<b.w; }
    12 void insert(int x,int y,int w) 
    13 {
    14     e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt,e[cnt].w=w;
    15     e[++cnt].to=x,e[cnt].from=head[y],head[y]=cnt,e[cnt].w=0;
    16 }
    17 int bfs() 
    18 {
    19     for(int i=1;i<=n;i++) d[i]=0,cur[i]=head[i];
    20     Q.push(S),d[S]=1;
    21     while (!Q.empty()) 
    22     {
    23         int u=Q.front(); Q.pop();
    24         for (int i=head[u];i;i=e[i].from) if (!d[e[i].to]&&e[i].w) d[e[i].to]=d[u]+1,Q.push(e[i].to);
    25     }
    26     return d[T];
    27 }
    28 int dfs(int x,int now) 
    29 {
    30     if (x==T||!now) return now;
    31     int flow=0,ff;
    32     for (int& i=cur[x];i;i=e[i].from)
    33         if (d[e[i].to]==d[x]+1) 
    34         {
    35             ff=dfs(e[i].to,min(now,e[i].w));
    36             if (ff<=0) continue;
    37             now-=ff,flow+=ff,e[i].w-=ff,e[i^1].w+=ff;
    38             if (!now) break;
    39         }
    40     return flow;
    41 }
    42 int main() 
    43 {
    44     scanf("%d%d%d",&n,&m,&k);
    45     for (int i=1;i<=m;i++) scanf("%d%d%d",&E[i].u,&E[i].v,&E[i].w);
    46     E[k].o=1,S=E[k].u,T=E[k].v,t=E[k].w,sort(E+1,E+m+1,cmp);
    47     for (int i=1;i<=m;i++) { if (E[i].o) break; insert(E[i].u,E[i].v,t-E[i].w+1),insert(E[i].v,E[i].u,t-E[i].w+1); }
    48     while (bfs()) ans+=dfs(S,999999999); printf("%d",ans);
    49 }
  • 相关阅读:
    字符串系列——Immediate Decodability
    Java I/O流操作(四)对象的序列化
    table自动拉伸在chrome与IE中的区别
    【web开发】spring+hibernate4支持中文排序
    SQL批量重命名中文字段名为对应拼音首字母字段名脚本
    Hibernate执行查询后又立马执行了更新(defaultaccess)
    上传图片之上传前预览图片
    挖掘FPTree
    Linux下Json库的编译及代码测试
    C语言中的位运算和逻辑运算
  • 原文地址:https://www.cnblogs.com/Comfortable/p/11280486.html
Copyright © 2020-2023  润新知