棋盘取数
Time Limit: 1000 MS Memory Limit: 32768 K
Total Submit: 66(22 users) Total Accepted: 18(11 users) Rating: Special Judge: No
Description
给你一个n*n的格子的棋盘,每个格子里面有一个非负数。现在从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大。
Input
包括多个测试实例,每个测试实例包括一个整数n 和n*n个非负数x(n<=20, 0 <= x <= 1000)。
Output
对于每个测试实例,输出可能取得的最大的和。
Sample Input
3
258 83 905
874 941 662
733 415 890
Sample Output
3727
题解:这是个二分图,求的是最大点权独立集。最大点权独立集=总权值-最小点权覆盖。设下标和为偶数的点为X,下表和为奇数的点为Y。则ss连x,流量为mp[x],y连tt,流量为mp[y].x连周围4个点,流量为INF。
代码:
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<algorithm>
#include<map>
#include<time.h>
#include<math.h>
//#define pb push_back
//#define mp make_pair
#define INF 0x3f3f3f3f
using namespace std;
typedef long long int ll;
typedef pair<int,int>pp;
const int N=1e3+100;
const int mod=1e9+7;
int read()
{
int x=0;
char ch = getchar();
while('0'>ch||ch>'9')ch=getchar();
while('0'<=ch&&ch<='9')
{
x=(x<<3)+(x<<1)+ch-'0';
ch=getchar();
}
return x;
}
/***********************************************************/
int fx[4]= {0,0,1,-1};
int fy[4]= {1,-1,0,0};
int t,n,m,u,v,c,ss,tt;
int cnt,sum;
struct node
{
int to,w,next;
} edge[N<<2];
int dep[N];
int vis[N];
int head[N<<2];
int mp[50][50];
void add(int f,int to,int w)
{
edge[cnt].to=to;
edge[cnt].w=w;
edge[cnt].next=head[f];
head[f]=cnt++;
}
int makedep()
{
memset(dep,0,sizeof(dep));
queue<int>s;
s.push(ss);
dep[ss]=1;
while(!s.empty())
{
int u=s.front();
if(u==tt) return 1;
s.pop();
for(int i=head[u]; i!=-1; i=edge[i].next)
{
int v=edge[i].to;
int w=edge[i].w;
if(w&&dep[v]==0)
{
dep[v]=dep[u]+1;
s.push(v);
}
}
}
return 0;
}
int dfs(int u,int maxflow,int tt)
{
if(u==tt) return maxflow;
int ret=0;
for(int i=head[u]; i!=-1; i=edge[i].next)
{
int v=edge[i].to;
int w=edge[i].w;
if(w&&dep[v]==dep[u]+1)
{
int f=dfs(v,min(maxflow-ret,w),tt);
edge[i].w-=f;
edge[i^1].w+=f;
ret+=f;
if(ret==maxflow) return ret;
}
}
return ret;
}
void Dinic()
{
int ans=0;
while(makedep()==1)
{
ans+=dfs(ss,INF,tt);
}
printf("%d\n",sum-ans);
}
void solve()
{
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
if((j+i)%2==0)
{
add(ss,(i-1)*n+j,mp[i][j]);
add((i-1)*n+j,ss,0);
}
else
{
add((i-1)*n+j,tt,mp[i][j]);
add(tt,(i-1)*n+j,0);
}
}
}
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
if((i+j)%2==1) continue;
else
{
for(int k=0; k<4; k++)
{
int x=i+fx[k];
int y=j+fy[k];
if(x>=1&&x<=n&&y>=1&&y<=n)
{
add((i-1)*n+j,(x-1)*n+y,INF);
add((x-1)*n+y,(i-1)*n+j,0);
}
}
}
}
}
}
int main()
{
while(~scanf("%d",&n))
{
cnt=0;
memset(head,-1,sizeof(head));
ss=n*n+1;
tt=ss+1;
sum=0;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
scanf("%d",&mp[i][j]);
sum+=mp[i][j];
}
}
solve();
Dinic();
}
return 0;
}