网络流入门题目 - bzoj 1001

现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,
而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:

 

左上角点为(1,1),右下角点为(N,M)(上图中N=4,M=5).有以下三种类型的道路 
1:(x,y)<==>(x+1,y) 
2:(x,y)<==>(x,y+1) 
3:(x,y)<==>(x+1,y+1) 
道路上的权值表示这条路上最多能够通过的兔子数,道路是无向的. 左上角和右下角为兔子的两个窝,
开始时所有的兔子都聚集在左上角(1,1)的窝里,现在它们要跑到右下解(N,M)的窝中去,狼王开始伏击
这些兔子.当然为了保险起见,如果一条道路上最多通过的兔子数为K,狼王需要安排同样数量的K只狼,
才能完全封锁这条道路,你需要帮助狼王安排一个伏击方案,使得在将兔子一网打尽的前提下,参与的
狼的数量要最小。因为狼还要去找喜羊羊麻烦.

Sample Output14


Input
第一行为N,M.表示网格的大小,N,M均小于等于1000.
接下来分三部分
第一部分共N行,每行M-1个数,表示横向道路的权值. 
第二部分共N-1行,每行M个数,表示纵向道路的权值. 
第三部分共N-1行,每行M-1个数,表示斜向道路的权值. 
输入文件保证不超过10M
Output

输出一个整数,表示参与伏击的狼的最小数量.

Sample Input
3 4
5 6 4
4 3 1
7 5 3
5 6 7 8
8 7 6 5
5 5 5
6 6 6
 
题意 : 题目是让求一个最小割,而最小割等于最大流,因此直接跑一个 dicnic 就可以了
代码示例 :
using namespace std;
#define ll long long
const int maxn = 1e6+5;
const int mod = 1e9+7;
const double eps = 1e-9;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;

int read() {                    //输入挂
    int x = 0, f = 1; register char ch = getchar();
    while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
    while (ch >= '0'&&ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    return x*f;
}

int n, m;
struct node
{
    int to, flow, next;
}edge[6*maxn];
int head[maxn];
int cnt = 0;

void addedge(int u, int v, int w){
    edge[cnt].next = head[u], edge[cnt].to = v, edge[cnt].flow = w, head[u] = cnt++;    
    edge[cnt].next = head[v], edge[cnt].to = u, edge[cnt].flow = w, head[v] = cnt++; 
}

int deep[maxn], que[maxn];
bool bfs(int s, int t){
    int head1 = 0, tail1 = 1;
    memset(deep, 0, sizeof(deep));
    que[0] = s; deep[s] = 1;
    
    while(head1 < tail1){
        int u = que[head1++];
        for(int i = head[u]; i != -1; i = edge[i].next){ 
            int v = edge[i].to;
            if (!deep[v] && edge[i].flow) {
                deep[v] = deep[u]+1;
                que[tail1++] = v;
            }
        }
    }
    return deep[t];
}

int dfs(int u, int f1){
    if (u == n*m || f1 == 0) return f1; // !!!!!
    
    int f = 0;
    for(int i = head[u]; i != -1; i = edge[i].next){
        int v = edge[i].to;
        if (edge[i].flow && deep[v] == deep[u]+1){
            int x = dfs(v, min(f1, edge[i].flow));
            edge[i].flow -= x; edge[i^1].flow += x;
            f1 -= x, f += x;
            if (f1 == 0) return f;
        }
    }
    if (!f) deep[u] = -2;
    return f;
}

void solve() {
    
    int res = 0;
    while(bfs(1, n*m)) {
        res += dfs(1, inf);
    } 
    cout << res << endl;
}

int main() { 
    n = read(), m = read();
    
    int i = 1, j = 2;
    int x;
    memset(head, -1, sizeof(head));
    for(int k = 1; k <= n*m; k++){
        if (i%m == 0) {i++, j++; continue;}
        x = read();
        addedge(i, j, x);
        i++, j++;
    }
    i = 1, j = 1+m;
    for(int k = 1; k <= (n-1)*m; k++){
        x = read();
        addedge(i, j, x);
        i++, j++;
    }
    i = 1, j = 2+m; 
    for(int k = 1; k <= (n-1)*m; k++){
        if (i%m == 0) {i++, j++; continue;}
        x = read();
        addedge(i, j, x);
        i++, j++;
    }
    solve();
    return 0;
}

 

转载于:https://www.cnblogs.com/ccut-ry/p/9885345.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值