[BZOJ1475] 方格取数 - 最小割

Description

在一个 \(n \times n\) 的方格里,每个格子里都有一个正整数。从中取出若干数,使得任意两个取出的数所在格子没有公共边,且取出的数的总和尽量大。 \(n \le 30\)

Solution

黑白染色后转化为最小割

黑点和 S 连边,白点和 T 连边,代价是数本身

相邻数之间连 \(\infty\)

#include 
using namespace std;
namespace flow
{

const int maxn = 200005;
const int inf = 1e+9;

int dis[maxn], ans, cnt = 1, s, t, pre[maxn * 10], nxt[maxn * 10], h[maxn], v[maxn * 10];
std::queue q;
void make(int x, int y, int z)
{
    pre[++cnt] = y, nxt[cnt] = h[x], h[x] = cnt, v[cnt] = z;
    pre[++cnt] = x, nxt[cnt] = h[y], h[y] = cnt;
}
bool bfs()
{
    memset(dis, 0, sizeof dis);
    q.push(s), dis[s] = 1;
    while (!q.empty())
    {
        int x = q.front();
        q.pop();
        for (int i = h[x]; i; i = nxt[i])
            if (!dis[pre[i]] && v[i])
                dis[pre[i]] = dis[x] + 1, q.push(pre[i]);
    }
    return dis[t];
}
int dfs(int x, int flow)
{
    if (x == t || !flow)
        return flow;
    int f = flow;
    for (int i = h[x]; i; i = nxt[i])
        if (v[i] && dis[pre[i]] > dis[x])
        {
            int y = dfs(pre[i], min(v[i], f));
            f -= y, v[i] -= y, v[i ^ 1] += y;
            if (!f)
                return flow;
        }
    if (f == flow)
        dis[x] = -1;
    return flow - f;
}
int solve(int _s,int _t)
{
    s=_s;
    t=_t;
    ans = 0;
    for (; bfs(); ans += dfs(s, inf));
    return ans;
}
}

using flow::make;
using flow::solve;

const int di[4]={0,0,1,-1};
const int dj[4]={1,-1,0,0};

const int N = 35;

int n, m, s, t, t1, t2, t3;
int a[N][N];

int id(int x,int y)
{
    return n*x-n+y;
}

int ok(int x,int y)
{
    return x>0 && y>0 && x<=n && y<=n;
}

int main()
{
    cin>>n;
    int sum=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cin>>a[i][j];
            if((i+j)%2) make(id(i,j),n*n+2,a[i][j]);
            else make(n*n+1,id(i,j),a[i][j]);
            if((i+j)%2==0) for(int k=0;k<4;k++)
            {
                int ni=i+di[k],nj=j+dj[k];
                if(ok(ni,nj))
                {
                    make(id(i,j),id(ni,nj),1e9);
                }
            }
            sum+=a[i][j];
        }
    }
    cout<

你可能感兴趣的:([BZOJ1475] 方格取数 - 最小割)