一个裸状态压缩DP~处理起来很烦人的题.
题目大意: http://acm.hdu.edu.cn/showproblem.php?pid=2167
给一个N*N的大方格,每个小方格上有一个值,选择了一个小方格那么就不能选择它周围的八个格子了.大格子周围是相连的(应该是个圆~~~),最右边的格子的右边按第一个算,对角线也不能选.N<=15.
解题思想:
一看15就知道是状态压缩了,首先纪录可行状态,在原可行状态的基础上,在生成适合当前行的可行状态.然后对于当前行的每一个状态更新下一行的所有可与当前状态兼容的状态.
源代码:
#include <myhead.h>
const int N=16;
const int M=(1<<N);
const int NUM=2583;
int n,m,num;
int state1[NUM],state[NUM];
int board[N+1][N+1];
int dp[2][NUM];
void build() {
num=0;
for(int i=0;i<M;++i) {
if(i&(i<<1)) {
continue;
}
state1[num++]=i;
}
}
bool init() {
char ch;
n=1;
while(1) {
if(scanf("%d%c",&board[1][n],&ch)==EOF)
return false;
n++;
if(ch=='\n') break;
}
n--;
//printf("%d\n",n);
int num1=(1<<n);
num=0;
for(int i=0;state1[i]<num1;++i) {
bool flag=((state1[i] & 1) | (state1[i] & (num1 >> 1)));
if(!flag || flag) {
state[num++]=state1[i];
}
}
//printf("%d\n",num);
for(int i=2;i<=n;++i) {
for(int j=1;j<=n;++j) {
scanf("%d",&board[i][j]);
}
}
return true;
}
int getDp(int k,int m) {
int t=1;
int sum=0;
while(m) {
if(m&1) {
sum+=board[k][t];
}
m>>=1;
t++;
}
return sum;
}
void work() {
memset(dp,0,sizeof(dp));
int *a=dp[0];
int *b=dp[1];
int ans=0;
//printf("%d\n",n);
for(int k=1;k<=n;++k) {
for(int i=0;i<num;++i) {
int sum=getDp(k,state[i]);
//printf("%d\n",sum);
int max=0;
for(int j=0;j<num;++j) {
if(state[j]&state[i]) continue;
int t=state[i]>>1;
if(state[j]&t) continue;
t=state[i]<<1;
if(state[j]&t) continue;
checkmax(a[j],b[i]+sum);
checkmax(ans,a[j]);
}
}
swap(a,b);
}
printf("%d\n",ans);
}
int main() {
build();
while(init()) {
work();
}
return 0;
}