poj1185

 1 /*状态压缩就是把一系列用二进制表示的状态压缩成一个十进制数*/
 2 #include<stdio.h>
 3 #include<string.h>
 4 #include<iostream>
 5 using namespace std;
 6 int s[65],dp[150][65][65],cont=0,sum[65],map[150];//m为10根据要求每行最多60中状态
 7 bool ok(int x)
 8 {
 9     if(x&(x<<1)) return false;//间隔1的不满足
10     if(x&(x<<2)) return false;//间隔2的不满足
11     return true;
12 }
13 int getsum(int x)//判断x有几个1,即这种状态能放多少大炮
14 {
15     int sum=0;
16     while(x>0)
17     {
18        if(x&1) sum++;
19         x>>=1;
20     }
21     return sum;
22 }
23 void init(int n)//初始化所有满足的状态
24 {
25     int i;
26     for(i=0;i<(1<<n);i++)
27         if(ok(i))
28         {
29             s[cont]=i;//记录满足的状态,大炮占的位置为1,山地 位置为0;
30             sum[cont++]=getsum(i);//记录这种状态可以放多少门大炮
31         }
32 }
33 int max(int a,int b)
34 {
35     if(a>b) return a;
36     return b;
37 }
38 int main()
39 {
40     int i,j,n,m,k,r;
41     
42     while(cin>>n>>m)
43     {
44         memset(dp,-1,sizeof(dp));
45         for(i=0;i<n;i++)
46         {
47             for(j=0;j<m;j++)
48             {
49                  char c;
50                 cin>>c;
51                 //printf("%c ",c);
52                 //if(j==m-1)     getchar();
53                 //a[i][j]=c;
54                 if(c=='H') map[i]|=(1<<j);//记录实际的地形,有山的位置为1;
55             }
56         }
57             init(m);
58             for(i=0;i<cont;i++)//特别判断第一行;
59                 if(!(s[i]&map[0])) //s[i]中大炮位置为1,map中山地位置为1,如果想与后的结果不为0说明大炮和山地位置相同,是不满足的,这行是筛选所有满足的状态中符合这个地形的
60                     dp[0][0][i]=sum[i];//前面的0,0代表第0行的没有前面两行,所以第0行的
61                 for(r=1;r<n;r++)
62                     for(i=0;i<cont;i++)//枚举第r行
63                     {
64                         if(s[i]&map[r]) continue;//剪枝,如果状态j不满足地形
65                         for(j=0;j<cont;j++)//枚举第r-1行
66                         {
67                             if(s[i]&s[j]) continue;//如果这两行的大炮在同一列
68                             for(k=0;k<cont;k++)//枚举第r-2行
69                             {
70                                 if(s[i]&s[k]) continue;//
71                                 if(dp[r-1][k][j]==-1) continue;//没这种状态存在
72                                 dp[r][j][i]=max(dp[r][j][i],dp[r-1][k][j]+sum[i]);
73                             }
74                         }
75                     }
76 
77                                   /*状态转移,从i到j,从k到j再从j到i,sum[i]是本行每种状态i的大炮个数,
78                                 j代表r-1行大炮的放法,i是本行的放法,因为这个关系是一层一层传下来的,
79                                 所以那么dp[r][j][i]代表的是从开始行到r行的最大炮个数,*/
80                     int ans = 0;
81                    for(i = 0; i < cont; i ++)
82                    for(j = 0; j <cont; j ++)
83                    ans = max(ans,dp[n-1][i][j]);
84                    printf("%d
",ans);
85     }
86       return 0;
87 }
88 
89     
90 /*
91 5 4
92 PHPP
93 PPHH
94 PPPP
95 PHPP
96 PHHP*/
原文地址:https://www.cnblogs.com/okboy/p/3227096.html