题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2167
题目大意:给你N*N的矩阵,让你从中取出一些数使他们的和最大,当选定一个数,这个数的八个方向的数都不能被取。
解题思路:预处理合法状态,状态转移方程和方格取数一样, dp[i][j]=max( dp[i][j] , dp[i-1][k]+ans[j] );即第i行的第j个状态是由 第i-1行的第k个状态递推而来,同时加上当前行 第j个状态的花费。
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[16][1600],map[16][16],sta[1600];
int n;
void init()
{
memset(dp,0,sizeof(dp));
memset(map,0,sizeof(map));
memset(sta,0,sizeof(sta));
}
void solve()
{
int num=(1<<n),ct=0;
for(int i=0;i<num;i++)
if( (i&(i<<1))==0 && (i&(i>>1))==0 )
sta[ct++]=i;
for(int i=1; i<=n; i++) //枚举行数
for(int j=0; j<ct; j++) //上一行的状态数
for(int k=0; k<ct; k++) //当前行的状态数
if( !(sta[k]&sta[j]) && !(sta[k]&(sta[j]<<1)) && !(sta[k]&(sta[j]>>1)) )
{
int sum=0;
for(int k1=0; k1<n; k1++)
if( sta[k]&(1<<k1) )
sum+=map[i][n-k1-1];
dp[i][k]=max(dp[i][k],dp[i-1][j]+sum);
}
int ans=0;
for(int i=0;i<ct;i++)
ans=max(ans,dp[n][i]);
printf("%d\n",ans);
}
int main()
{
char s[100];
while(gets(s))
{
init();
int t=strlen(s);
n=0;
for(int i=0;i<t;i+=3)
map[1][n++]=(s[i]-'0')*10+s[i+1]-'0';
for(int i=2;i<=n;i++)
for(int j=0;j<n;j++)
scanf("%d",&map[i][j]);
solve();
getchar();getchar();
}
return 0;
}