这道题的题意还是比较好理解的,就是不能取相邻的两个数,使所有取出来的数的总和最大。。
嗯,先不要急着想搜索、暴力或贪心(虽然有可能可以过,如果可以,欢迎指教),这题可是出自网络流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;
}