=== ===
这里放传送门
=== ===
题解
一开始写这个题的时候看到什么“可以任意选择起点”还“可以停一秒”还有什么“奇数秒偶数秒”就感到八脸懵逼。。。实际上它说的“周围格子会消失”就是在告诉你如果对格子黑白染色,选了一个格子周围跟它颜色不同的那些格子就都不能选了,它说的“可以任意选择起点”还有“可以停一秒”就是在告诉你每次选择的时候可以任意决定当前选择黑点还是白点。并且如果它不能任意选择起点或者不能停一秒的话结果就没有可变性了还做个毛线。。那这就变成了一个显然的最小割问题,最后用所有格子的价值之和减去最小割就是答案。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#define inc(x)(x=(x%100000)+1)
#define inf 1000000000
using namespace std;
int n,m,cnt,tot,a[110][110],num[110][110],p[10010],S,T,sum,Flow,cur[10010],d[10010];
struct edge{
int to,flw,nxt;
}e[500010];
void add(int from,int to,int flow){
e[tot].to=to;e[tot].flw=flow;e[tot].nxt=p[from];p[from]=tot++;
}
bool Bfs(){
int q[100010],head,tail;
memset(d,-1,sizeof(d));
head=0;tail=1;
for (int i=S;i<=T;i++) cur[i]=p[i];
q[tail]=S;d[S]=0;
while (head!=tail){
int u;
inc(head);u=q[head];
for (int i=p[u];i!=-1;i=e[i].nxt)
if (e[i].flw>0&&d[e[i].to]==-1){
int v=e[i].to;
d[v]=d[u]+1;inc(tail);q[tail]=v;
}
}
return d[T]!=-1;
}
int Dinic(int u,int Min){
if (u==T||Min==0) return Min;
int r;
for (int i=cur[u];i!=-1;i=e[i].nxt){
int v=e[i].to;cur[u]=i;
if (e[i].flw>0&&d[v]==d[u]+1&&(r=Dinic(v,min(Min,e[i].flw)))){
e[i].flw-=r;e[i^1].flw+=r;return r;
}
}
return 0;
}
int main()
{
memset(p,-1,sizeof(p));
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++){
scanf("%d",&a[i][j]);
num[i][j]=++cnt;sum+=a[i][j];
}
S=0;T=n*m+1;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if ((i+j)%2==0){
int w=num[i][j];
add(S,w,a[i][j]);add(w,S,0);
if (i!=n){add(w,num[i+1][j],inf);add(num[i+1][j],w,0);}
if (j!=m){add(w,num[i][j+1],inf);add(num[i][j+1],w,0);}
if (i!=1){add(w,num[i-1][j],inf);add(num[i-1][j],w,0);}
if (j!=1){add(w,num[i][j-1],inf);add(num[i][j-1],w,0);}
}else{
add(num[i][j],T,a[i][j]);add(T,num[i][j],0);
}
while (Bfs()){
int r;
while (r=Dinic(S,0x7fffffff))
Flow+=r;
}
printf("%d\n",sum-Flow);
return 0;
}