给你一个m*n的格子的棋盘,每个格子里面有一个非负数。
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大。
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大。
Input
包括多个测试实例,每个测试实例包括2整数m,n和m*n个非负数(m<=50,n<=50)
Output
对于每个测试实例,输出可能取得的最大的和
Sample Input
3 3 75 15 21 75 15 28 34 70 5
Sample Output
188
很有意思的图论建模,首先生成一个二分图,左边的点和右边的点不可同时取。然后从超级源点向左边的每一个点连一条流量为该处数字的边,左边的点向自己上下左右四个右边的点连一条流量为无限的边,右边的点向超级汇点连该出数字流量的边。再Dinic跑一遍最大流就可以了。
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=150;
const int inf=0x3f3f3f3f;
struct edge
{
int v,next,flow;
}e[1000100];
int head[maxn*maxn];
int iter[maxn*maxn];
int d[maxn*maxn];
bool colblk[maxn][maxn];//是否从原点出发
int edc;
int n,m;
int mp[maxn][maxn];
void adde(int u,int v,int f)
{
e[edc].v=v;
e[edc].flow=f;
e[edc].next=head[u];
head[u]=edc++;
}
void addn(int u,int v,int f)
{
adde(u,v,f);adde(v,u,0);
}
int getn(int x,int y)
{
return (x-1)*n+y;
}
void init()
{
edc=0;
memset(head,-1,sizeof(head));
}
bool legal(int x,int y)
{
return !(x<1 || x>m || y<1 || y>n);
}
int bfs(int s,int t)
{
queue<int> q;
memset(d,-1,sizeof(d));
memcpy(iter,head,sizeof(head));
d[s]=0;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].v,f=e[i].flow;
if(d[v]==-1 && f)
{
d[v]=d[u]+1;
q.push(v);
}
}
}
return d[t]!=-1;
}
int dfs(int u,int mn,int t)
{
if(u==t)
return mn;
int ret=0;
for(int &i=iter[u];i!=-1;i=e[i].next)
{
int v=e[i].v;
int f=e[i].flow;
if(!f || d[v]!=d[u]+1)
continue;
int tmp=dfs(v,min(mn-ret,f),t);
if(!tmp) continue;
e[i].flow-=tmp;
e[i^1].flow+=tmp;
ret+=tmp;
if(ret==tmp)
return ret;
}
return ret;
}
int dinic(int s,int t)
{
int ans=0;
while(bfs(s,t)) ans+=dfs(s,inf,t);
return ans;
}
int main()
{
while(~scanf("%d%d",&m,&n))
{
init();
int sum=0;
int s=0,t=n*m+1;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
{
scanf("%d",&mp[i][j]);
sum+=mp[i][j];
if((i%2==1 && j%2==1)||(i%2==0 && j%2==0))
addn(s,getn(i,j),mp[i][j]),colblk[i][j]=1;
else
addn(getn(i,j),t,mp[i][j]),colblk[i][j]=0;
}
int dx[4]={0,0,-1,1};
int dy[4]={-1,1,0,0};
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
{
for(int k=0;k<4;k++)
if(legal(i+dx[k],j+dy[k]))
if(colblk[i][j]==1)
addn(getn(i,j),getn(i+dx[k],j+dy[k]),inf);
else
addn(getn(i+dx[k],j+dy[k]),getn(i,j),inf);
}
printf("%d\n",sum-dinic(s,t));
}
return 0;
}
rockdu
没有帐号? 立即注册