棋盘取数 | ||||||
| ||||||
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 | ||||||
Source | ||||||
2014暑假集训练习赛(8月13日) |
思路
1、首先,这个题是一个二分图模型。并且我们知道最大权独立集=总权-最小割=总权-最大流。
2、那么我们就在以上基础建图。
①我们将点分成两个集合,i+j为偶数的点我们规定为一个集合,那么i+j为奇数的点就是另一个集合。
②源点S和i+j为偶数的点都进行建边,其容量为a【i】【j】,i+j为奇数的点和汇点t都进行建边,其容量也是a【i】【j】;
③将i+j为偶数的点和周围四个点进行建边,其容量为无穷大。
3、求一遍最大流,其解为:总权-最大流、
4、Ford_Fulkerson 、Edmond _Karp都是不可行算法(数据将两种算法都卡了TLE)。
Ac:
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
int head[100000];
struct EdgeNode
{
int to;
int w;
int next;
}e[1000000];
int div[100000];
int a[25][25];
int fx[4]={0,0,1,-1};
int fy[4]={1,-1,0,0};
int n,cont,ss,tt;
void add(int from,int to,int w)
{
e[cont].to=to;
e[cont].w=w;
e[cont].next=head[from];
head[from]=cont++;
}
void getmap()
{
ss=n*n+1;
tt=ss+1;
cont=0;
memset(head,-1,sizeof(head));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if((i+j)%2==0)
{
add(ss,(i-1)*n+j,a[i][j]);
add((i-1)*n+j,ss,0);
}
else
{
add((i-1)*n+j,tt,a[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;
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 makediv()
{
memset(div,0,sizeof(div));
div[ss]=1;
queue<int >s;
s.push(ss);
while(!s.empty())
{
int u=s.front();
if(u==tt)return 1;
s.pop();
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
int w=e[i].w;
if(w&&div[v]==0)
{
div[v]=div[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=e[i].next)
{
int v=e[i].to;
int w=e[i].w;
if(w&&div[v]==div[u]+1)
{
int f=Dfs(v,min(maxflow-ret,w),tt);
e[i].w-=f;
e[i^1].w+=f;
ret+=f;
if(ret==maxflow)return ret;
}
}
return ret;
}
int Dinic()
{
int ans=0;
while(makediv()==1)
{
ans+=Dfs(ss,INF,tt);
}
return ans;
}
int main()
{
while(~scanf("%d",&n))
{
int output=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&a[i][j]);
output+=a[i][j];
}
}
getmap();
output-=Dinic();
printf("%d\n",output);
}
}