最小割

最小割

什么是最小割?
一个割就是一组边的集合,将给集合边从图中边集合中移除,那么图被分割为两个部分,这两个部分之间没有任何边连接。
如何找到这个最小割?
当一个图被割分成两个部分时,不再存在S到T的通路,所以割的代价必定大于等于图的最大流(这个需要添加额外说明吗?应该不需要吧,算是非常明显的结论了吧)。那么也就是说,割的代码最小不能小于图的最大流,也就是割的代价等于图的最大流。

例题1
题意:每次操作可以让除了一条边之外的所有边-1,问让一条边必定出现在最小生成树上的最小操作数是多少。

思路:
1.由于是最小生成树,只与边权大小有关,操作等价于让本条边加1。
2.让目标边为树的一条边,那么就肯定是让比它边权小的一直加,知道恰好大于它的边权为止。
3.s-t不连通的前提是比它小的边形成的图不能联通,这不就是最小割吗?代价就是w[i]-w[id]+1;

    scanf("%d%d%d",&n,&m,&id);
    for(int i=1; i<=m; i++)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        a[i]=u,b[i]=v,c[i]=w;
    }
    s=a[id],t=b[id];
    for(int i=1;i<=m;i++)
    {
        if(i==id)continue;
        if(c[i]>c[id])continue;
        add(a[i],b[i],c[id]-c[i]+1);
        add(b[i],a[i],c[id]-c[i]+1);
    }
    printf("%d\n",ac.Dinic());
  • 1.最小割点

  • 2.最大权闭合子图

1.最小点割集是指:给出一张有向图(无向图)和两个点 ST 每个点都有一个正数点权,求一个不包含点S T 的权值和最小的点集使得删掉点集中的所有点后,S 无法到达T 。

求法:对于这个问题,我们将每一个点拆成两个点,一个为入点,一个为出点,这两个点之间有一条边权为原图中点权的有向边,从入点指向出点。对于原图中的边x→y ,我们转化成出点到入点的连边,x+n→y,y+n→x;
在转化完的图上跑最小割就是原图的最小点割集

    scanf("%d%d",&n,&m);
    scanf("%d%d",&s,&t);
    t=t+n;
    for(int i=1;i<=n;i++)
        scanf("%d",&val[i]);
    for(int i=1;i<=m;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        add(u+n,v,INF);
        add(v,u+n,0);
        add(v+n,u,INF);
        add(u,v+n,0);
    }
    for(int i=1;i<=n;i++)
        add(i,i+n,val[i]),add(i+n,i,0);
    printf("%d\n",ac.Dinic());

2.最大权闭合子图:有一个有向图,每一个点都有一个权值(可以为正或负或0),选择一个权值和最大的子图,使得每个点的后继都在子图里面,这个子图就叫最大权闭合子图。
在这里插入图片描述
能选的子图有Ø,{4},{3,4},{2,4},{1,2,3,4},它们的权值分别为0,-1,5,-6,4.
所以最大权闭合子图为{3,4},权值为5.
结论:最大权闭合子图=正权值和-最小割

    scanf("%d%d",&n,&m);
    s=n+m+1,t=n+m+2;
    for(int i=1; i<=n; i++)
        scanf("%d",&val[i]);
    for(int i=1; i<=n; i++)
        add(i,t,val[i]),add(t,i,0);
    int sum=0;
    for(int i=1; i<=m; i++)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        add(n+i,u,INF),add(u,n+i,0);
        add(n+i,v,INF),add(v,n+i,0);
        add(s,n+i,w),add(n+i,s,0);
        sum+=w;
    }
    printf("%d\n",sum-ac.Dinic());
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值