• [BZOJ1475] 方格取数


    Description

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

    Solution

    黑白染色后转化为最小割

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

    相邻数之间连 (infty)

    #include <bits/stdc++.h>
    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<int> 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<<sum-solve(n*n+1,n*n+2)<<endl;
    }
    
    
    
  • 相关阅读:
    leetcode--95. Unique Binary Search Trees II
    leetcode--96. Unique Binary Search Trees
    leetcode分类总结
    leetcode-115. Distinct Subsequences
    tcpdump安装配置及抓包分析
    dp经典案例
    tree的各种问题
    大数的阶乘算法
    由mmap引发的SIGBUS
    win10系统下如何查看端口被哪个进程占用
  • 原文地址:https://www.cnblogs.com/mollnn/p/13211134.html
Copyright © 2020-2023  润新知