ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【ICPC-Beijing 2006】狼抓兔子

2021-11-09 08:01:09  阅读:246  来源: 互联网

标签:Beijing cnt return int LL 最小 ICPC 2006 sum


引理:最小割最大流定理

搜了一圈没有找到什么是最小割,然后懵了。

首先,什么是割?其实,割 \(=\) 割边 \(=\) 去掉以后使图不连通的边的集合。

然后,容量和最少的割集称为最小割。对于割,有这样一个重要定理:

最小割 \(=\) 最大流。

嗯,最小割就这么多东西。为什么正确?这里给出一种直观的想法。(原 PO):

  1. 最大流不可能大于最小割,因为最大流所有的水流都一定经过最小割那些割边,流过的水流怎么可能比水管容量还大呢?
  2. 最大流不可能小于最小割,如果小,那么说明水管容量没有物尽其用,可以继续加大水流.

证毕。

思路

这里首先说一个技巧,无向图的网络流在建边时反向弧直接建成权值为v的边即可,因为这样的边一开始就是可以增广的。

题意是求一个无向图的最小割,然后我们运用最小割-最大流定理,可以转化成求最大流的问题。不过朴素的 Dinic 是会 \(\color{#052242}{\text{TLE}}\) 的,这里提供一种优化方法:

我们知道,假定在一次 Dinic 过程中,发现不能再进行增广了,那么就相当于向下的这条路是废的。因此,我们可以直接把这条路堵上,然后就可以过了。

代码

#include<bits/stdc++.h>
#define LL long long
const LL N=8e6+5,inf=1e9;
using namespace std;
struct edge {
    LL to,nxt,w;
} e[N];
LL s,t,cnt=1,head[N],d[N];
void add(LL u,LL v,LL w) {
    e[++cnt].to=v,e[cnt].w=w,e[cnt].nxt=head[u],head[u]=cnt;
}
bool bfs() {
    queue<LL> q;
    q.push(s),memset(d,0,sizeof(d)),d[s]=1;
    while(q.size()) {
        LL x=q.front();
        q.pop();
        for(LL i=head[x]; i; i=e[i].nxt) {
            LL v=e[i].to;
            if(e[i].w>0&&!d[v]) {
                q.push(v),d[v]=d[x]+1;
                if(v==t) {
                    return 1;
                }
            }
        }
    }
    return 0;
}
LL dfs(LL x,LL sum) {
    if(x==t) {
        return sum;
    }
    LL res=0;
    for(int i=head[x]; i&&sum; i=e[i].nxt) {
        int v=e[i].to;
        if(!e[i].w||d[v]!=d[x]+1) {
            continue;
        }
        int k=dfs(v,min(sum,e[i].w));
        if(!k) {
            d[v]=-1;
        }
        e[i].w-=k,e[i^1].w+=k,res+=k,sum-=k;
    }
    return res;
}
LL n,m;
int turn(int x,int y) {
    return m*(x-1)+y;
}
int main() {
    scanf("%lld %lld",&n,&m),s=1,t=turn(n,m);
    for(int i=1; i<=n; i++) {
        for(int j=1,w; j<m; j++) {
            scanf("%d",&w),add(turn(i,j),turn(i,j+1),w);
            add(turn(i,j+1),turn(i,j),w);
        }
    }
    for(int i=1; i<n; i++) {
        for(int j=1,w; j<=m; j++) {
            scanf("%d",&w),add(turn(i,j),turn(i+1,j),w);
            add(turn(i+1,j),turn(i,j),w);
        }
    }
    for(int i=1; i<n; i++) {
        for(int j=1,w; j<m; j++) {
            scanf("%d",&w),add(turn(i,j),turn(i+1,j+1),w);
            add(turn(i+1,j+1),turn(i,j),w);
        }
    }
    LL ans=0;
    while(bfs()) {
        ans+=dfs(s,inf);
    }
    printf("%lld",ans);
    return 0;
}

参考资料:网络流学习笔记(三) 最小割 平面图转对偶图 - LiRewriter 的博客 - 洛谷博客

标签:Beijing,cnt,return,int,LL,最小,ICPC,2006,sum
来源: https://www.cnblogs.com/AFewMoon/p/15527141.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有