Bzoj P1001 [BeiJing2006]狼抓兔子___最小割

题目大意:

一堆兔子要从点[1,1]走到点[N,M],给出所有横行路径,纵行路径,对角线路径所能容纳的兔子数K,如果要封锁一条路径,则需要同样的K只狼,问在将兔子一网打尽的前提下,参与的狼的数量要最小,这个最小值是多少。

N,M均小于等于1000.

题解:

这题是一道很显然的最小割问题,
因为最小割等于最大流,
所以我们建边然后跑一波最大流即可
注意建边的数组要开2*3*N*M,不然会炸

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define INF 0xfffffff
#define N 1000005

using namespace std;

queue <int> Q;
struct node{
   int to,next,w;
}a[8*N];
int ls[N],d[N],n,m,maxflow=0,cnt=1,S,T;

void add(int u , int v , int w){
    cnt++; a[cnt].to = v; a[cnt].next = ls[u]; a[cnt].w = w; ls[u] = cnt;
    cnt++; a[cnt].to = u; a[cnt].next = ls[v]; a[cnt].w = w; ls[v] = cnt;
}

bool bfs(){
    while (Q.size()) Q.pop();
    for (int i = S; i <= T; i++) d[i] = 0;
    d[S] = 1;
    Q.push(S);
    while (Q.size()){
           int u = Q.front();
           Q.pop();
           for (int i = ls[u]; i ; i =a[i].next)
                if (a[i].w && !d[a[i].to]){
                    d[a[i].to] = d[u]+1;
                    Q.push(a[i].to);
                    if (a[i].to == T) return 1;
                }
    }
    return 0;
}

int dfs(int dep , int flow){
    if (dep == T) return flow;
    int rest = flow,rp = 0;
    for (int i = ls[dep]; i && rest ; i = a[i].next)
         if (d[a[i].to] == d[dep]+1 && a[i].w){
             rp = dfs(a[i].to , min(a[i].w , rest));
             if (!rp) d[a[i].to] = 0;
             a[i].w -= rp;
             a[i^1].w += rp;
             rest -= rp;    
         }
     return flow - rest;
}

void dinic(){
    int flow;
    while (bfs()){
           while (flow = dfs(S,INF)) maxflow += flow;
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    int cost;
    S=1; T=n*m;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m-1; j++){
             scanf("%d",&cost);
             add(m*(i-1)+j , m*(i-1)+j+1 , cost);
        }

    for (int i = 1; i <= n-1; i++)
         for (int j = 1; j <= m; j++){
              scanf("%d",&cost);
              add(m*(i-1)+j , m*i+j , cost);
         }

    for (int i = 1; i <= n-1; i++)
         for (int j = 1; j <= m-1; j++){
              scanf("%d",&cost);
              add(m*(i-1)+j , m*i+j+1 , cost);
         }

    dinic();
    printf("%d\n" , maxflow);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值