洛谷P2774_方格取数问题_最大流_最小割

题目大意

m * n 的矩阵中取数,不能取相邻的数,求能取得的数的和最大为多少。

思路

(i, j) 为 i 行 j 列的单元格,根据 i + j 的奇偶性将节点分为两个集合,在矩阵中相邻得节点分别在图的两侧,得一个二分图。

s 点向左侧节点建边,容量为节点在矩阵中的值。

右侧节点向t 建边,容量为节点在矩阵中的值。

左侧节点向在矩阵中相邻的右侧节点建立容量为INF的边。

进入S集的右侧节点不取,进入T集的左侧节点不取,所得的最小割的值即为不取的数的和。

ans = sum - max_flow

左侧节点a和右侧节点b,如果在矩阵中相邻,则必须同时进入S集或T集,也就是说,a和b不能同时取得(如果同时进入S集则取a不取b)。因此建图时,a和b之间的边容量为INF,INF的边不能进入割集。

选择a和b进入S集或T集的过程是同过 比较a和b的权值 决策取舍a和b的过程。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#define INF 0x3f3f3f3f
#define rep0(i, n) for (int i = 0; i < n; i++)
#define rep1(i, n) for (int i = 1; i <= n; i++)
#define rep_0(i, n) for (int i = n - 1; i >= 0; i--)
#define rep_1(i, n) for (int i = n; i > 0; i--)
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define mem(x, y) memset(x, y, sizeof(x))
#define MAXN 110
using namespace std;
typedef long long ll;
const int S = 0, T = MAXN * MAXN - 1;
struct Edge
{
    int to, cap, flow, rev;
};
vector<Edge> g[MAXN * MAXN];
int grid[MAXN][MAXN], m, n;
int idx(int i, int j)
{
    return i * n + j + 1;
}
void addEdge(int u, int v, int cap)
{
    g[u].push_back((Edge){v, cap, 0, g[v].size()});
    g[v].push_back((Edge){u, 0, 0, g[u].size() - 1});
}
int level[MAXN * MAXN], itr[MAXN * MAXN];
queue<int> q;
void bfs()
{
    mem(level, -1);
    q.push(S);
    level[S] = 0;

    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        for (int i = 0; i < g[u].size(); i++)
        {
            Edge e = g[u][i];
            if (level[e.to] < 0 && e.cap > e.flow)
            {
                level[e.to] = level[u] + 1;
                q.push(e.to);
            }
        }
    }

}
int dfs(int u, int f)
{
    if (u == T)
        return f;
    for (int& i = itr[u]; i < g[u].size(); i++)
    {
        Edge& e = g[u][i];
        if (level[e.to] > level[u] && e.cap > e.flow)
        {
            int d = dfs(e.to, MIN(f, e.cap - e.flow));

            if (d)
            {
                e.flow += d;
                g[e.to][e.rev].flow -= d;
                return d;
            }
        }
    }
    return 0;
}
ll max_flow()
{
    ll flow = 0;
    while (true)
    {
        bfs();
        if (level[T] < 0)
            return flow;
        ll f;
        mem(itr, 0);

        while ((f = dfs(S, INF)) > 0)
        {
            flow += f;
        }
    }
}
int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
    #endif // ONLINE_JUDGE
    ll ans = 0;
    scanf("%d %d", &m, &n);
    for (int i = 0; i < m; i++)
        for (int j = 0; j < n; j++)
        {
            scanf("%d", &grid[i][j]);
            ans += grid[i][j];
        }

    for (int i = 0; i < m; i++)
    {
        for (int j = 0; j < n; j++)
        {
            if ((i + j) & 1)
            {
                addEdge(idx(i, j), T, grid[i][j]);
                if (i - 1 >= 0)
                    addEdge(idx(i - 1, j), idx(i, j), INF);
                if (j - 1 >= 0)
                    addEdge(idx(i, j - 1), idx(i, j), INF);
            }
            else
            {
                addEdge(S, idx(i, j), grid[i][j]);
                if (i - 1 >= 0)
                    addEdge(idx(i, j), idx(i - 1, j), INF);
                if (j - 1 >= 0)
                    addEdge(idx(i, j), idx(i, j - 1), INF);
            }



        }
    }


    ans -= max_flow();


    printf("%lld\n", ans);




    return 0;
}

猜你喜欢

转载自blog.csdn.net/Anna__1997/article/details/81101546