HDU 3046【最小割】

题目大意:在一个n*m的矩阵上,1代表羊,2代表狼,0代表平地,我们有长度为1的一个栅栏(不是放在格子上的,是放在格子和格子之间的空隙上的),问使用最少的栅栏,能够使得狼吃不到羊。

又学到了一招,以前一直以为建图是要先设好S点T点,在把其他的点和他们两一一相连。今天学到了原来可以在整个map上根据条件建好图,再把其中的某些目标点和源汇点相连的。

思路如下:

1、建立最小割模型:
①建立源点S,将源点S连入各个有狼的节点上,权值设定为INF,表示狼可以从任意方向出发。
②建立汇点T,将各个羊节点连入汇点T,权值设定为INF。
③将每两个相邻的格子之间建立一条边,权值设定为1,表示如果拆掉了这条边,这条边就不能走了

#include<stdio.h>
#include<string.h>
#include<queue>
#include<iostream>
#define MAX 400000
#define INF 0x1f1f1f1f
using namespace std;
int map[210][210];
int ss, tt;
int n, m;
int cont;
int head[MAX];
int d[4][2] = { {0,1},{0,-1},{-1,0},{1,0} };
int divv[MAX];
int cur[MAX];
struct edge {
    int from, to, w, next;

}e[MAX];

void add(int u, int v, int w) {
    e[cont].from = u;
    e[cont].to = v;
    e[cont].w = w;
    e[cont].next = head[u];
    head[u] = cont++;
}

int makediv() {
    memset(divv, 0, sizeof(divv));
    divv[ss] = 1;
    queue<int> Q;
    Q.push(ss);
    while (!Q.empty()) {
        int u = Q.front();
        if (u == tt)
            return 1;
        Q.pop();
        for (int i = head[u]; i != -1; i = e[i].next) {
            int w = e[i].w;
            int v = e[i].to;
            if (divv[v] == 0 && w) {
                divv[v] = divv[u] + 1;
                Q.push(v);
            }
        }

    }
    return 0;

}

int DFS(int u, int maxflow, int tt) {
    if (u == tt)
        return maxflow;
    int ret = 0;
    for (int &i = cur[u]; i != -1; i = e[i].next) {
        int v = e[i].to;
        int w = e[i].w;
        if (divv[v] == divv[u] + 1 && w) {
            int f = DFS(v, min(maxflow - ret, w), tt);
            e[i].w -= f;
            e[i ^ 1].w += f;
            ret += f;
            if (ret == maxflow)
                return ret;

        }
    }
    return ret;
}

int kase = 0;
void Dinic() {
    int ans = 0;

    while (makediv() == 1) {
        memcpy(cur, head, sizeof(head));
        ans += DFS(ss, INF, tt);
    }
    printf("Case %d:\n%d\n", ++kase, ans);
}

int main(void) {
    kase = 0;
    while (~scanf("%d%d", &n, &m)) {
        memset(head, -1, sizeof(head));
        cont = 0;
        ss = 0;
        tt = n * m + 1;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                scanf("%d", &map[i][j]);
                if (map[i][j] == 2) {
                    //每只狼都可以从任意方向出发
                    add(ss, (i - 1)*m + j, INF);
                    add((i - 1)*m + j, ss, 0);
                }
                if (map[i][j] == 1) {
                    add((i - 1)*m + j, tt, INF);
                    add(tt, (i - 1)*m + j, 0);
                }

            }

        }
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                for (int t = 0; t < 4; t++) {
                    int xx = i + d[t][0];
                    int yy = j + d[t][1];
                    if (xx > 0 && xx <= n && yy > 0 && yy <= m) {
                        add((i - 1)*m + j, (xx - 1)*m + yy, 1);
                        add((xx - 1)*m + yy, (i - 1)*m + j, 0);

                    }
                }

            }

        }

        Dinic();

    }

    return 0;

}

原文地址:https://www.cnblogs.com/tennant/p/8977023.html

时间: 2024-10-06 11:47:12

HDU 3046【最小割】的相关文章

hdu 3046 最小割

每个栅栏其实就是一条边,修一些栅栏,使得狼不能抓到羊,其实就是求一个割,使得羊全在S中,狼全在T中. 1 #include <cstdio> 2 #include <cstring> 3 #include <vector> 4 #include <queue> 5 #define maxn 40010 6 #define oo 0x3f3f3f3f 7 #define clr(arr,n) memset(&arr,0,sizeof(arr[0])*(

Pleasant sheep and big big wolf (hdu 3046 最小割)

Pleasant sheep and big big wolf Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2371    Accepted Submission(s): 988 Problem Description In ZJNU, there is a well-known prairie. And it attracts p

hdu 3657 最小割的活用 / 奇偶方格取数类经典题 /最小割

题意:方格取数,如果取了相邻的数,那么要付出一定代价.(代价为2*(X&Y))(开始用费用流,敲升级版3820,跪...) 建图:  对于相邻问题,经典方法:奇偶建立二分图.对于相邻两点连边2*(X&Y),源->X连边,Y->汇连边,权值w为点权. ans=总点权-最小割:如果割边是源->X,表示x不要选(是割边,必然价值在路径上最小),若割边是Y-汇点,同理:若割边是X->Y,则表示选Y点且选X点, 割为w( 2*(X&Y) ). 自己的确还没有理解其本质

There is a war (hdu 2435 最小割+枚举)

There is a war Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 970    Accepted Submission(s): 277 Problem Description There is a sea. There are N islands in the sea. There are some directional

hdu 3204(最小割--关键割边)

Ikki's Story I - Road Reconstruction Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 7491   Accepted: 2172 Description Ikki is the king of a small country – Phoenix, Phoenix is so small that there is only one city that is responsible fo

hdu 5076 最小割灵活的运用

题意比较复杂,其实关键是抽象出来:每个点,可以赋予俩个值(二选一,必需选一个,设ai,bi).  求所有之和最大,有条件:若俩个点同时满足: 1,:点的二进制只有一位不同.  2:至少有一个是选B值: 则可获得对应加成. 这题开始想了半天,建图遇到问题,看了官方说是最小割,于是入手: a值就是小于阈值的最大值,B值就是大于等于的最大值. 思路:俩个点选其一,必然想到建二分(每个点一分为二)图,中间连无穷的边.因为只有一位不同,必然分奇偶点,有奇数个1的点,源点到他为A值,对应点到汇点为B值,偶点

hdu 1565 最小割

黑白染色,源指向白,黑指向汇,容量都是方格中数的大小,相邻的格子白指向黑,容量为oo,然后求一次最小割. 这个割是一个简单割,如果只选择不在割中的点,那么一种割就和一个选数方案一一对应,割的大小就是不选的那些数的大小,我们需要最小化这个值. 答案=总和-最小割 1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <vector> 5 #define maxn 410 6

Being a Hero (hdu 3251 最小割 好题)

Being a Hero Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1211    Accepted Submission(s): 381 Special Judge Problem Description You are the hero who saved your country. As promised, the ki

HDU 3526 最小割

点击打开链接 题意:有两个公司分别提供的n个部件,每个部件的价格给出,现在要这买n个部件,我可以选择两个公司中的任意一个,但是对于下面给的m个关系来说,若满足i与j不再同一个公司,那么就要加上c的费用,问买n个部件的最小花费 思路:刚刚读完题的时候感觉像是最小费用流呐,流量就是5呗,然后根据关系建图,画了一会也画不出来,看了一下正解竟然是最小割,思想到时很简单,但是思路不对的话还是很难想到的,建图就是源点,中间一列n个部件,然后汇点,源点连中间的话就是A公司的n个物品,然后中间连汇点的话就是B公

hdu 1569 最小割

和HDU 1565是一道题,只是数据加强了,貌似轮廓线DP来不了了. 1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <vector> 5 #define maxn 2510 6 #define oo 0x3f3f3f3f 7 using namespace std; 8 9 struct Edge { 10 int u, v, f; 11 Edge( int u,