[POJ1185][NOI2001]炮兵阵地 状压DP
题目链接:http://poj.org/problem?id=1185
很裸的状压,考虑对于一行用二进制储存每一种的状态,但是状态太多了做不了。
观察到有很多状态都是不合法的,于是我们预处理出合法的状态,发现只有60种,然后随便DP一下就可以了。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 int N,M; 6 char G[110][15]; 7 int s[65],cnt[65],scnt=0,ban[65]; 8 int f[110][65][65]; 9 int main(){ 10 memset(ban,0,sizeof(ban)); 11 memset(f,0,sizeof(f)); 12 memset(cnt,0,sizeof(cnt)); 13 memset(s,0,sizeof(s)); 14 scanf("%d%d",&N,&M); 15 for(int i=1;i<=N;i++) scanf("%s",G[i]); 16 for(int i=1;i<=N;i++) 17 for(int j=0;j<M;j++) 18 if(G[i][j]=='H') 19 ban[i]|=(1<<j); 20 int tmp=1<<M; 21 for(int i=0;i<tmp;i++){ 22 bool flag=true; 23 for(int j=0;j<M;j++){ 24 int tmp=((i&(1<<j))>0)+((i&(1<<j+1))>0)+((i&(1<<j+2))>0); 25 if(tmp>1){ 26 flag=false; 27 break; 28 } 29 } 30 if(flag){ 31 s[++scnt]=i; 32 for(int j=0;j<M;j++) 33 if(i&(1<<j)) 34 cnt[scnt]++; 35 } 36 } 37 for(int i=1;i<=scnt;i++) 38 if((s[i]&ban[1])==0) 39 f[1][1][i]=cnt[i]; 40 for(int i=1;i<=scnt;i++) 41 if((s[i]&ban[2])==0) 42 for(int j=1;j<=scnt;j++) 43 if((s[i]&s[j])==0&&(s[j]&ban[1])==0) 44 f[2][j][i]=max(f[2][j][i],f[1][1][j]+cnt[i]); 45 for(int i=3;i<=N;i++) 46 for(int j=1;j<=scnt;j++) 47 if((s[j]&ban[i-2])==0) 48 for(int k=1;k<=scnt;k++) 49 if((s[j]&s[k])==0&&(s[k]&ban[i-1])==0) 50 for(int t=1;t<=scnt;t++) 51 if((s[j]&s[t])==0&&(s[k]&s[t])==0&&(s[t]&ban[i])==0) 52 f[i][k][t]=max(f[i][k][t],f[i-1][j][k]+cnt[t]); 53 int Ans=0; 54 for(int i=1;i<=scnt;i++) 55 for(int j=1;j<=scnt;j++) 56 Ans=max(Ans,f[N][i][j]); 57 printf("%d\n",Ans); 58 return 0; 59 }