这道题我是看了大神的题解后,自己再写的。主要思路就是用二进制来记录表示取或者不取,一行行的进行计算,用一个数组记录上一行的所有取法,一个数组记录现在这行的所有取法,如果取法进行与运算为1的话,那么就代表有相邻的而不进行计算,然后这样一直DP到最后一行便可以得到最后的结果。代码如下:
#include<stdio.h>
#include<string.h>
#define M 100000
int map[22][22];
int n;
int nowSize;
int preSize;
int now[M]; //以二进制的形式存现在这一行取数的各种情况
int pre[M]; //以二进制的形式存上一行取数的各种情况
int ans[M]; //现在这一行每一种情况所取数的和
int dp[M];
int temp[M];
int Max(int a,int b){
if(a<b)return b;
else return a;
}
void Dfs(int row,int k,int p,int sum){
if(k>=n){ //超过n则可以记录这个状态
now[++nowSize]=p;
ans[nowSize]=sum;
}
else {
Dfs(row,k+2,p|(1<<k),sum+map[row][k]); /*这个位置取了,那么就要加上这个位的二进制,通过或运算得出,
这个位置取了的话,那么下一个要取的至少要跳两格*/
Dfs(row,k+1,p,sum); //这个位置不取并跳一格
}
}
void DP(){
int i,j,k;
for(k=0;k<n;k++){
nowSize=0;
Dfs(k,0,0,0); //搜出此行的所有状态
for(i=1;i<=nowSize;i++)
dp[i]=0;
for(i=1;i<=nowSize;i++){
for(j=1;j<=preSize;j++){
if(now[i]&pre[j])continue; //相与为1,证明有相邻而不继续往下
dp[i]=Max(dp[i],temp[j]+ans[i]);
}
}
for(i=1;i<=nowSize;i++){ //目前这行的状态保存为上一行
pre[i]=now[i];
temp[i]=dp[i];
}
preSize=nowSize;
}
}
int main()
{
int i,j;
while(scanf("%d",&n)!=EOF){
for(i=0;i<n;i++){
for(j=0;j<n;j++){
scanf("%d",&map[i][j]);
}
}
preSize=1;
pre[1]=0;
temp[1]=0; //这三个语句主要用来在dp中初始化的
DP();
int m=0;
for(i=1;i<=preSize;i++){
m=(temp[i]>m)?temp[i]:m;
}
printf("%d\n",m);
}
return 0;
}