HDU-1569 方格取数(2) 最小割最大流

  题义很简单,还记得方格取数(1)的时候,使用状态压缩写的,这里由于行列数太大,因此无法进行压缩。所以要运用的最小割最大流的思想来解这道题。

  大概是这样分析的,题义是要我们求在一个方格内取出N个点,使得这N个独立的(不相邻)点集的和最大。我们可以将问题转化为最小割来求解。首先,我们将方格进行黑白相间的染色,然后再将任意一种颜色(黑色)作为源点,一种颜色(白色)作为汇点。我们的算法过程就是一个不断寻找增广路的过程。当我们找到最大流的时,也就是此时不存在从黑色到白色的路径,也即不存在不相邻的两个方格能够连通了。而此时的最大流就是分割两个区间的最小割,拿总合值减去这个最小割就是我们想要得到的结果。  

代码如下:

#include <cstring>

#include <cstdlib>

#include <cstdio>

#include <queue>

#define RE(x) (x)^1

#define INF 0x3fffffff

#define MAXN 50

using namespace std;



int N, M, dis[MAXN*MAXN+10], head[MAXN*MAXN+10], idx, source, sink;

int G[MAXN+10][MAXN+10];



int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};



struct Edge

{

    int v, cap, next;

}e[200000];



void init()

{

    idx = -1;

    source = N*M, sink = N*M+1;

    memset(head, 0xff, sizeof (head));

}



int to(int x, int y)

{

    return (x-1)*M+y-1;

}



void insert(int a, int b, int c)

{

    ++idx;

    e[idx].v = b, e[idx].cap = c;

    e[idx].next = head[a], head[a] = idx;

}



bool judge(int x, int y)

{

    if (x < 1 || x > N || y < 1 || y > M) {

        return false;

    }

    else {

        return true;

    }

}



bool bfs()

{

    int u;

    queue<int>q;

    memset(dis, 0xff, sizeof (dis));

    dis[source] = 0;

    q.push(source);

    while (!q.empty()) {

        u = q.front();

        q.pop();

        for (int i = head[u]; i != -1; i = e[i].next) {

            if (dis[e[i].v] == -1 && e[i].cap > 0) {

                dis[e[i].v] = dis[u] + 1;

                q.push(e[i].v);

            }

        }

    }

    return dis[sink] != -1;

}



int dfs(int u, int flow)

{

    if (u == sink) {

        return flow;

    }

    int tf = 0, sf;

    for (int i = head[u]; i != -1; i = e[i].next) {

        if (dis[u]+1 == dis[e[i].v] && e[i].cap > 0 && (sf = dfs(e[i].v, min(flow-tf, e[i].cap)))) {

            e[i].cap -= sf, e[RE(i)].cap += sf;

            tf += sf;

            if (tf == flow) {

                return flow;

            }

        }

    }

    if (!tf) {

        dis[u] = -1;

    }

    return tf;

}



int Dinic()

{

    int ans = 0;

    while (bfs()) {

        ans += dfs(source, INF);

    }

    return ans;

}





int main()

{

    int sum;

    while (scanf("%d %d", &N, &M) == 2) {

        sum = 0;

        init();

        for (int i = 1; i <= N; ++i) {

            for (int j = 1; j <= M; ++j) {

                scanf("%d", &G[i][j]);

                sum += G[i][j];

            }

        }

        for (int i = 1; i <= N; ++i) {

            for (int j = 1; j <= M; ++j) {

                if (!((i+j)&1)) {  

                    insert(source, to(i, j), G[i][j]);

                    insert(to(i, j), source, 0);

                    for (int k = 0; k < 4; ++k) {

                        int xx = i+dir[k][0], yy = j+dir[k][1];  

                        if (judge(xx, yy)) {

                            insert(to(i, j), to(xx, yy), G[i][j]);

                            insert(to(xx, yy), to(i, j), 0);

                        }

                    }

                } 

                else {

                    insert(to(i, j), sink, G[i][j]);

                    insert(sink, to(i, j), 0);

                }

            }

        }

        printf("%d\n", sum - Dinic());

    }

    return 0;

}

你可能感兴趣的:(HDU)