题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1565
题意:给你N*N的方格中取数,但不能取相邻的数,(上下左右相邻都不行),求可以取的数之和的最大值。
思路:一道状压dp入门题,因为给的n并不大,我们用一个n位二进制数来表示这一行的n个数取与不取的状态,因为一行之间相邻的不能取,所有我们可以把不符合的数全部筛选除去(i&i>>1)=0就是符合要求的数,不然就是不符合要求的数,原因很简单,我们把i右移一位之后再与原来的数&一下,如果有相邻的1存在,那么i右移一位之后就会1的位置就会对齐,那么&之后就肯定不会是0,删一我们可以用这种方法筛选出符合要求的数,行与行之间,也是一样的道理,假设第i行状态为j,第i-1行状态为k,那么如果符合要求,那么i&j=0,最后我们找出最大值的就可以了。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;
int dp[25][20000];
int tot[20000];
int a[25][25];
int fin(int i,int x)
{
int t=1;
int sum=0;
while(x)
{
if(x&1)
{
sum+=a[i][t];
}
x/=2;
t++;
}
return sum;
}
int main()
{
int n;
while(~scanf("%d",&n))
{
memset(dp,0,sizeof(dp));
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
scanf("%d",&a[i][j]);
}
}
int cut=0;
for(int i=0; i<(1<<n); i++)
{
if((i&(i>>1))==0)
{
tot[++cut]=i;
}
}
for(int i=1; i<=n; i++)
{
for(int j=1; j<=cut; j++)
{
int va=fin(i,tot[j]);
for(int k=1; k<=cut; k++)
{
if((tot[j]&tot[k])==0)
dp[i][j]=max(dp[i][j],dp[i-1][k]+va);
}
}
}
int ma=0;
for(int i=1; i<=cut; i++)
{
ma=max(ma,dp[n][i]);
}
printf("%d\n",ma);
}
return 0;
}