【题意】给定一个N*N的方格,让你在里面取出一些数使其和最大,要求每一个数不能与其相邻的8个数同时取出
【解题方法】状压DP。dp[i][j]表示第i行状态为j可以得到的最大取值,转移易得为dp[i][j] = max(dp[i][j], dp[i-1][k] + sum[i][j])。
【期望复杂度】O(1579*n*1579)
【代码君】别忘了这坑爹的getchar。。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int dp[22][40000];
int sum[22][40000];//合法状态的数和
int s[40000];//合法的状态被保存在这里
int a[22][22], b[22], n, m;
char str[110];
int main()
{
b[0] = 1;
for(int i = 1; i < 16; i++) b[i] = b[i-1] * 2;
while(gets(str)){
int le = strlen(str);
n = 0;
for(int i = 0; i < le; i += 3){
a[0][n++] = (str[i] - '0') * 10 + (str[i+1] - '0');
}
for(int i = 1; i < n; i++){
m = 0;
gets(str);
for(int j = 0; j < le; j += 3){
a[i][m++] = (str[j] - '0') * 10 + (str[j+1] - '0');
}
}
memset(dp, 0, sizeof(dp));
memset(sum, 0, sizeof(sum));
int cnt = 0;
for(int i = 0; i < (1<<n); i++){
if((i<<1)&i) continue;
s[cnt++] = i;
}
//deal sum
for(int i = 0; i < n; i++){
for(int j = 0; j < cnt; j++){
for(int k = 0; k < n; k++){
if(b[k]&s[j]){
sum[i][j] += a[i][k];
}
}
}
}
//INIT
for(int i = 0; i < cnt; i++) dp[0][i] = sum[0][i];
//DP
for(int i = 1; i < n; i++){
for(int j = 0; j < cnt; j++){
for(int k = 0; k < cnt; k++){
if(s[j] & s[k]) continue;
if(s[j] & (s[k]<<1)) continue;
if(s[j] & (s[k]>>1)) continue;
dp[i][j] = max(dp[i][j], dp[i-1][k]+sum[i][j]);
}
}
}
int ans = 0;
for(int i = 0; i < cnt; i++){
ans = max(ans, dp[n-1][i]);
}
printf("%d\n",ans);
getchar();
}
return 0;
}