方格取数(1)
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 7386 Accepted Submission(s): 2806
Problem Description
给你一个n*n的格子的棋盘,每个格子里面有一个非负数。
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大。
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大。
Input
包括多个测试实例,每个测试实例包括一个整数n 和n*n个非负数(n<=20)
Output
对于每个测试实例,输出可能取得的最大的和
Sample Input
3 75 15 21 75 15 28 34 70 5
Sample Output
188
解题关键:黑白染色。(横纵坐标相加分成奇,偶两部分),构造超级源点,汇点。原点到奇数点的权值为该点上的值,奇数点到相邻点的权值为INF,偶数点到汇点的权值为该点的值。求最小割。
最小割=最大流。
ans=总数的和-最小割。
最小割=最大流。
ans=总数的和-最小割。
#include <iostream>
#include<string.h>
using namespace std;
#include<queue>
#define INF 0x7fffffff
#define MS(a,b) memset(a,b,sizeof(a))
int mat[505][505],n,s,t,dis[300000],f,head[500005];
#define MAXN 3000
#include<algorithm>
struct node
{
int to,next,w;
}edge[500005];
void add(int u,int v,int w)
{
edge[f].to=v;
edge[f].next=head[u];
edge[f].w=w;
head[u]=f++;
edge[f].to=u;
edge[f].w=0;
edge[f].next=head[v];
head[v]=f++;
}
int bfs()
{
int i,x,v;
MS(dis,-1);
dis[s]=0;
queue<int>q;
q.push(s);
while(!q.empty())
{
x=q.front();
q.pop();
for(i=head[x];i!=-1;i=edge[i].next)
{ v=edge[i].to;
if(edge[i].w&&dis[v]==-1)
{
dis[v]=dis[x]+1;
if(v==t)return 1;
q.push(v);
}
}
}
return 0;
}
int dfs(int s,int cur_flow)
{
int i,v,tmp,dt=cur_flow;//dt为当前剩余流量。
if(s==t)return cur_flow;
for(i=head[s];i!=-1;i=edge[i].next)
{
v=edge[i].to;
if(edge[i].w&&dis[s]==dis[v]-1)
{
int flow=dfs(v,min(dt,edge[i].w));//一条增广路,能够增广的流量,只能是路上最小流量边的流量
edge[i].w-=flow;//减少前向弧流量
edge[i^1].w+=flow;//增加后向弧流量
dt-=flow;//找到一条路,存起来
}
}
return cur_flow-dt;//一共增广的流量
}
int dinic()
{
int ans=0;
while(bfs())
ans+=dfs(s,INF);
return ans;
}
int main()
{
int i,j,sum,k,i1,j1;
while(cin>>n)
{
t=n*n+n+1;
f=sum=0;
s=1;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
cin>>mat[i][j];
sum=sum+mat[i][j];
}
MS(head,-1);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
if((i+j)%2==1)
{
add(1,i*n+j,mat[i][j]);
if(i+1<=n)
add(i*n+j,(i+1)*n+j,INF);
if(i-1>=1)
add(i*n+j,(i-1)*n+j,INF);
if(j+1<=n)
add(i*n+j,i*n+j+1,INF);
if(j-1>=1)
add(i*n+j,i*n+j-1,INF);
}
else
add(i*n+j,t,mat[i][j]);
}
cout<<sum-dinic()<<endl;
}
return 0;
}