题目
onmylove n×m网格上发明了一种游戏。每个网格上都有一个正整数。现在你可以从格子里取出数字,使你的最终得分尽可能高。获得分数的方法是
以下几点:
●在一开始,比分是0;
●如果你把一个数等于x,分数增加x;
●后如果出现两个相邻空网格数量,那么分数应该下降了2(x&y). 这里x和y是过去存在于这两个网格上的值。请注意,“相邻网格”是指这两个网格之间存在且仅存在一个公共边界。
由于onmylove认为这个问题太简单了,他又增加了一条规则:
●在你开始游戏之前,你有一些立场和这些位置上的数字必须带走。
你能帮onmylove计算一下吗:onmylove在游戏中最高得分是多少?
输入
多个输入病例。对于每一种情况,一行有三个整数n m k。
n和m描述网格的大小n×m。k表示有k个位置你必须取它们的数字。然后n行后,每个包含m数字,代表n×m网格上的数字。然后是k行。每一行包含两个整数,表示一个位置的行和列
你必须记下这个位置的数字。而且,行和列是从1开始计数的。
限制:1≤n m≤50 0 k≤≤n×m,每个准备的整数不超过1000人。
输出
对于每个测试用例,在一行中输出最高分。
Sample Input
2 2 1
2 2
2 2
1 1
2 2 1
2 7
4 1
1 1
Sample Output
4
9
最小割…奇偶建图
有些点是必须选的 这些点为偶格子则向s连INF的边 奇格子向t连INF的边
覆盖原来的边 导致原来的边不会被割,割了也没用 INF在这儿撑着呢 就代表这个点必选
#include <queue>
#include <cstring>
#include <cstdio>
#define m(a,b) memset(a,b,sizeof a)
using namespace std;
typedef long long ll;
const int N=2500+5;
const int INF=0x3f3f3f3f;
struct Edge{int to,len,nex;}edge[N*8];
int head[N],d[N],a[N][N];
int tot,s,t,n,m;
void add(int from,int to,int len)
{
edge[++tot]=(Edge){to,len,head[from]};head[from]=tot;
edge[++tot]=(Edge){from,0,head[to]};head[to]=tot;
}
queue<int>q;
bool bfs()
{
while(!q.empty())
q.pop();
m(d,0);
q.push(s);
d[s]=1;
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=head[x];i;i=edge[i].nex)
{
int y=edge[i].to,l=edge[i].len;
if(!d[y]&&l)
{
d[y]=d[x]+1;
q.push(y);
if(y==t)
return 1;
}
}
}
return 0;
}
int dinic(int x,int flow)
{
if(x==t)
return flow;
int res=flow,k;
for(int i=head[x];i&&res;i=edge[i].nex)
{
int y=edge[i].to,l=edge[i].len;
if(l&&d[y]==d[x]+1)
{
k=dinic(y,min(res,l));
if(!k)
{
d[y]=0;
continue;
}
edge[i].len-=k;
edge[i^1].len+=k;
res-=k;
}
}
return flow-res;
}
int main()
{
int n,m,k;
while(~scanf("%d%d%d",&n,&m,&k))
{
m(head,0);
tot=1;
s=0,t=n*m+1;
ll sum=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]),sum+=a[i][j];
while(k--)
{
int i,j;
scanf("%d%d",&i,&j);
int pos=(i-1)*m+j;
if((i+j)&1)
add(pos,t,INF);
else
add(s,pos,INF);
}
for(int i=1;i<=n;i++)
{
if(!(i&1))
add((i-1)*m+1,t,a[i][1]);
for(int j=(i&1)?1:2;j<=m;j+=2)
{
int pos=(i-1)*m+j;
add(s,pos,a[i][j]);
if(j<m)
add(pos+1,t,a[i][j+1]);
if(i>1)
add(pos,pos-m,2*(a[i][j]&a[i-1][j]));
if(i<n)
add(pos,pos+m,2*(a[i][j]&a[i+1][j]));
if(j>1)
add(pos,pos-1,2*(a[i][j]&a[i][j-1]));
if(j<m)
add(pos,pos+1,2*(a[i][j]&a[i][j+1]));
}
}
ll maxflow=0;
while(bfs())
maxflow+=dinic(s,INF);
printf("%lld\n",sum-maxflow);
}
}