poj 1185(状压dp)
题目链接:http://poj.org/problem?id=1185
思路:状态压缩经典题目,dp[i][j][k]表示第i行状态为j,(i-1)行状态为k时最多可以放置的士兵个数,于是我们可以得到递推方程:dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][l]+num[j]);(其中num[j]为该状态下可以放置的士兵的个数。至于具体怎么分析,这位大牛讲的很清楚:http://www.cnblogs.com/scau20110726/archive/2013/02/27/2935256.html
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 7 int dp[111][77][77]; 8 int row[111]; 9 int s[1<<12];//保存所有士兵合法的状态 10 int num[1<<12]; 11 int n,m,ans,state; 12 char str[111]; 13 14 int Get_Num(int x) 15 { 16 int cnt=0; 17 while(x>0){ 18 cnt++; 19 x=x&(x-1); 20 } 21 return cnt; 22 } 23 24 int main() 25 { 26 while(~scanf("%d%d",&n,&m)){ 27 memset(row,0,sizeof(row)); 28 memset(dp,0,sizeof(dp)); 29 memset(num,0,sizeof(num)); 30 for(int i=0;i<n;i++){ 31 scanf("%s",str); 32 for(int j=0;j<m;j++){ 33 if(str[j]=='H')row[i]=(row[i]<<1)|1; 34 else row[i]<<=1; 35 } 36 } 37 state=0; 38 for(int i=0;i<(1<<m);i++){ 39 if((i&(i<<1))||(i&(i<<2)))continue; 40 s[state]=i; //合法状态 41 num[state++]=Get_Num(i);//可以放置的士兵个数 42 } 43 for(int i=0;i<state;i++){ 44 if(s[i]&row[0])continue; 45 dp[0][i][0]=num[i]; 46 } 47 for(int i=1;i<n;i++){ 48 for(int j=0;j<state;j++){ 49 if(row[i]&s[j])continue; 50 for(int k=0;k<state;k++){ 51 if(s[j]&s[k])continue; //i行与i-1行士兵相互攻击 52 for(int l=0;l<state;l++){ 53 if(s[j]&s[l])continue;//i行与i-2行士兵相互攻击 54 if(s[k]&s[l])continue;//i-1行与i-2行士兵相互攻击 55 dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][l]+num[j]); 56 } 57 } 58 } 59 } 60 ans=0; 61 for(int i=0;i<state;i++){ 62 for(int j=0;j<state;j++){ 63 ans=max(ans,dp[n-1][i][j]); 64 } 65 } 66 printf("%d\n",ans); 67 } 68 return 0; 69 } 70 71 72 73 74 75 76