题意:
给你一个n*n的格子的棋盘,每个格子里面有一个非负数。从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大。
思路:
定义 dp[ i ][ j ]表示第 i 行选择 j 的最大值。
选择 j指的是把j化为二进制,选择对应位值为1的。
比如 dp[1][5] , 5 二进制: 0000101,代表选择第一行第5个,和第一行第7个(自左到右数)。
dp[i][j] = max(dp[i-1][k] + get(j) ) get(j) 表示i行选则 j 的值 ,i-1行选择k 和 i行选择 j 不能冲突。
可以先预处理一下,把每行能选择的 j 给 弄出来,存起来。
原题链接:点击打开链接
#include <iostream>
#include <string.h>
using namespace std;
int dp[25][1<<20],a[25][25],legal[1<<20],num;
int max(int a,int b)
{
return a>b?a:b;
}
void build(int n)
{
int i,s=1<<n;
num=0;
for(i=0;i<s;i++)
{
if((i & (i>>1))||(i & (i<<1)))
continue;
legal[num++]=i;
}
}
int get(int i,int j,int k)
{
int sum=0;
while(j)
{
if(j%2)
sum+=a[i][k];
k--;
j/=2;
}
return sum;
}
int main()
{
int n,i,j,k;
while(cin>>n)
{
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
cin>>a[i][j];
}
}
build(n);
int ans=0;
for(i=0;i<n;i++)
{
for(j=0;j<num;j++)
{
if(i==0)
{
dp[i][j]=get(i,legal[j],n-1);
ans=max(ans,dp[i][j]);
}
else
{
int temp=-1;
for(k=0;k<num;k++)
{
if(legal[j] & legal[k])
continue;
temp=max(temp,dp[i-1][k]);
}
dp[i][j]=temp+get(i,legal[j],n-1);
ans=max(ans,dp[i][j]);
}
}
}
cout<<ans<<endl;
}
return 0;
}