传送门

这道题的题意还是比较好理解的,就是不能取相邻的两个数,使所有取出来的数的总和最大。。

嗯,先不要急着想搜索、暴力或贪心(虽然有可能可以过,如果可以,欢迎指教),这题可是出自网络流24题的呀。
所以肯定是用网络流

我们可以想象着把坐标和为奇数的点涂黑,其余点涂白,这样的话所有的同色点都是不相邻的。然后把所有的黑色点与源点相连,剩下的点和汇点相连。从源点连向黑点的边的权值(容量)是那个黑点的值,然后从白点连向汇点的边也是权值。然后黑点周围的白点是不能和黑点相连的,我们就把权值设为无限大,

我们要求的是什么呢,没错,选出来的所有点的权值最大…… 这TMD和这图有什么关系啊?

别心急,这题应该是要求最大点权独立集(注意:是点权),就等于所有点的值减去最小点权覆盖集,就是减去最小割(最大流),然后我们就可以开心地写代码了。

可能有些同学并不理解最后一句话是什么意思(其实一开始我也不理解)。

其实是这样的,我们相当与把点权转换为了边权,我们的目的是断开一些边,使得没有路径从源点到达汇点(为了满足题目的限制条件吗),然后我们要使断开的边的权值之和最小(断开的边就相当于是不选那个点,就是剩下的边权之和最大->这就是我们要求的答案嘛),乍一看,这不就是最小割吗?因为最小割=最大流,所以我们可以跑一遍最大流,然后用总的边权减去最大流就是我们的答案了,是不是很棒棒。

做完这题,我对网络流的理解又加深了一层。我们要巧妙的利用网络流的建模技巧(这也是网络流的精髓),把问题转换为可以用网络流解决的问题,要多刷题,刷好题,才能掌握技巧。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e5+10;
const int inf = 0x3f3f3f3f;
int n,m,s,t,tol,head[maxn],dep[maxn],x[50][50];
struct Edge
{
    int v,w,nxt;
}E[maxn];
void add_edge(int u,int v,int w)
{
    E[tol] = Edge{v,w,head[u]};
    head[u] = tol++;
}
void insert(int u, int v, int c)
{
    add_edge(u, v, c);
    add_edge(v, u, 0);
}
bool Bfs()
{
    memset(dep,0, sizeof(dep));
    queue<int>q;
    while(!q.empty())
        q.pop();
    q.push(s);
    dep[s] = 1;
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        for(int i = head[u];i != -1;i = E[i].nxt)
        {
            if(E[i].w && !dep[E[i].v])
            {
                dep[E[i].v] = dep[u] + 1;
                q.push(E[i].v);
                if(E[i].v == t)
                    return true;
            }
        }
    }
    return false;
}
int Dfs(int u,int f)
{
    if(u == t)
        return f;
    int used = 0,d = 0;
    for(int i = head[u];i != -1;i = E[i].nxt)
    {
        if(dep[u] == dep[E[i].v] - 1 && E[i].w)
        {
            if((d = Dfs(E[i].v,min(f - used,E[i].w))))
            {
                used += d;
                E[i].w -= d;
                E[i^1].w += d;
            }
        }
    }
    if(!used)
        dep[u] = 0;
    return used;
}
int Dinic()
{
    int max_flow = 0,d;
    while(Bfs())
    {
        while((d = Dfs(s,inf)))
            max_flow += d;
    }
    return max_flow;
}
signed main()
{
    //freopen("in","r",stdin);
    ios::sync_with_stdio(false);
    cin.tie(0);
    memset(head,-1, sizeof(head));
    int ans = 0,sz = 0;
    s = 0,t = 10000;
    cin >> m >> n;
    for(int i = 1;i <= m; i++)
    {
        for(int j = 1;j <= n; j++)
        {
            sz++;
            cin >> x[i][j];
            ans += x[i][j];
            if((i + j) & 1)
            {
                insert(s,sz,x[i][j]);
                if(i > 1)
                    insert(sz,sz - n,inf);
                if(i < m)
                    insert(sz,sz + n,inf);
                if(j > 1)
                    insert(sz,sz - 1,inf);
                if(j < n)
                    insert(sz,sz + 1,inf);

            }
            else
                insert(sz,t,x[i][j]);
        }
    }
    cout << ans - Dinic() << endl;
    return 0;
}