首页 > 代码库 > worf eat sheep, 最小割, hdu3046

worf eat sheep, 最小割, hdu3046

原题在此:http://acm.hdu.edu.cn/showproblem.php?pid=3046

小小思路:寒假一月月赛遇到的题,最小割、最大流的建图一般都是加一个源点S,汇点T

                   然后S与worf的边权值连INF,sheep与T的边权值为INF

                   这样总能确保最小割划分时worf在S一边,sheep在T一边

                  然后便是一个建图过程。  一个点的上下左右若是坐标合法,则各连权值为1的边。

ps:自己一开始始终理解不了题意,原来只要能把sheep围住即可,fence应该是建在两个坐标(空地与空地,狼与空地,羊与空地都可)之间。

      最小割定义:起点在S中,终点在T中的所有边的容量和。   (蓝图论书上说的净流量有问题)


附个代码。

//小trick,maxn开的应该大于n*m
//一开始自己老是以为是200左右。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>

using namespace std;

#define clr(x) memset(x,0,sizeof(x))
#define fp1 freopen("in.txt","r",stdin)
#define fp2 freopen("out.txt","w",stdout)
#define pb push_back

#define INF 0x3c3c3c3c
typedef long long LL;

const int maxn = 50000 + 10; //结点最多数目,
struct Edge{ //代表一条from->to容量为cap,流量为flow的弧
    int from, to, cap, flow;
};

struct Dinic{
    int n, m, s, t;   //结点数,边数(包括反向弧), 源点、汇点号
    vector<Edge> edges; //边表  edge[e]与edge[e^1]互为反向弧
    vector<int> G[maxn];
    bool vis[maxn];
    int d[maxn];
    int cur[maxn];

    void AddEdge(int from, int to, int cap){
        edges.push_back((Edge){from, to, cap, 0});
        edges.push_back((Edge){to, from, 0, 0});
        int m = edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }

    bool BFS(){
        memset(vis, 0, sizeof(vis));
        queue<int> Q;
        Q.push(s);
        d[s] = 0;
        vis[s] = 1;
        while(!Q.empty()){
            int x = Q.front();  Q.pop();
            for(int i = 0;i < G[x].size();i++){
                Edge& e = edges[G[x][i]];
                if(!vis[e.to] && e.cap>e.flow){
                    vis[e.to] = 1;
                    d[e.to] = d[x] + 1;
                    Q.push(e.to);
                }
            }
        }
        return vis[t];
    }

    int DFS(int x, int a){
        if(x==t || a==0)  return a;
        int flow = 0, f;
        for(int &i = cur[x];i < G[x].size();i++){
            Edge& e = edges[G[x][i]];
            if(d[x]+1==d[e.to] && (f=DFS(e.to, min(a, e.cap-e.flow)))>0){
                e.flow += f;
                edges[G[x][i]^1].flow -= f;
                flow += f;
                a -= f;
                if(a == 0) break;
            }
        }
        return flow;
    }

    int Maxflow(int s, int t){
        this->s = s;  this->t = t;
        int flow = 0;
        while(BFS()){
            memset(cur, 0, sizeof(cur));
            flow += DFS(s, INF);
        }
        return flow;
    }
};

int n, m;
int a[205][205];
int pos[205][205];
int wcnt, scnt;
int R(int i, int j){
    if(i<=n&&i>=0&&j>=0&&j<=m) return 1;
    else return 0;
}

int main()
{
    //fp1;
    int ncase = 1;
    while(scanf("%d %d", &n, &m) == 2){
//        wcnt = 1, scnt = 1;
          int i,j,k,l;
        clr(a);
        for(i = 1;i <= n;i++){
            for(j = 1;j <= m;j++){
                scanf("%d", &a[i][j]);
            }
        }

        int s = 0, t = n*m+1;
        Dinic test;
        for(i = 1;i <= n;i++){
            for(j = 1;j <= m;j++){
              int te = (i-1)*m+j;
              if(i<n) test.AddEdge(te,te+m,1);
              if(i>1) test.AddEdge(te,te-m,1);
              if(j<m) test.AddEdge(te,te+1,1);
              if(j>1) test.AddEdge(te,te-1,1);
              if(a[i][j]==1) test.AddEdge(te,t,INF);
              if(a[i][j]==2) test.AddEdge(s,te,INF);
            }
        }
        printf("Case %d:\n",ncase++);
        printf("%d\n", test.Maxflow(s,t));

    }
    return 0;
}