B - 炮兵阵地 POJ - 1185

 刚开始接触状压dp, 感觉就形式上来说还是比较固定的,和数位dp差不多,但是各种位运算还是不够熟练,用起来有点不是得心应手

还是得多练练,这部分代码还不是很好写。

 

题意: 中文题, 不多说了。

思路: dp[n][prestate][preprestate] 表示第n行的时候的状态是由前两行的状态推倒出的 

转移方程: dp[i][j][k] = max(dp[i][j][k], dp[i-1][k][t] + num[j]);

接下来就是看代码了,里面注释都有

 1 #include <string.h>
 2 #include <algorithm>
 3 #include <stdio.h>
 4 #include <string>
 5 #include <iostream>
 6 using namespace std;
 7 
 8 int dp[101][1025][1025];
 9 int a[1025];
10 int n, m;
11 int vnum;
12 int num[1025], vst[1025];
13 
14 int getsum(int i) {    // __builtin_popcount(i)
15     int res = 0;
16     while (i) {
17         i &= i - 1;
18         ++res;
19     }
20     return res;
21 }
22 
23 void initialState() {//vst数组记录的是对于每一行符合题目要求的安防方法 num记录的是对应安防方法的安防炮兵个数
24     vnum = 0;
25     for (int i = 0; i < (1 << m); ++i) {
26         if (!(i&(i << 1)) && !(i&(i << 2))) {            
27             vst[vnum] = i;
28             num[vnum++] = getsum(i);
29             cout << vst[vnum - 1] << ends << num[vnum - 1] << endl;
30         }
31     }
32 }
33 
34 int main() {
35     ios::sync_with_stdio(false);
36     while (cin >> n >> m) {
37         for (int i = 0; i < n; ++i) {
38             a[i] = 0;
39             for (int j = 1; j <= m; ++j) {
40                 char c; cin >> c;
41                 a[i] = a[i] * 2 + (c == 'P');
42             }
43         }
44         for (int i = 0; i <= n; ++i)
45             for (int j = 0; j <= 61; ++j)
46                 for (int k = 0; k <= 61; ++k)
47                     dp[i][j][k] = -1;
48         initialState();
49         for (int i = 0; i < vnum; ++i)
50             if (!(vst[i] & (~a[0])))
51                 dp[0][i][0] = num[i];
52         for (int i = 1; i < n; ++i) {
53             for (int j = 0; j < vnum; ++j) {
54                 if ((~a[i]) & vst[j]) continue;            //判断当前行vit[j]中1的集合是不是属于a[i]的集合
55                 for (int k = 0; k < vnum; ++k) {
56                     if ((~a[i - 1])&vst[k]) continue;    //对于上一行同样的判断
57                     if (vst[j] & vst[k]) continue;        //上下相邻两行得符合题目要求
58                     for (int t = 0; t < vnum; ++t) {
59                         if (vst[j] & vst[t]) continue;
60                         if (-1 == dp[i - 1][k][t]) continue;
61                         dp[i][j][k] = max(dp[i][j][k], dp[i-1][k][t] + num[j]); //状态转移方程
62                     }
63                 }
64             }
65         }
66         int res = 0;
67         for (int i = 0; i < vnum; ++i) {
68             for (int j = 0; j < vnum; ++j) {
69                 if (dp[n - 1][i][j] > res)
70                     res = dp[n - 1][i][j];
71             }
72         }
73         cout << res << endl;
74     }
75     return 0;
76 }

 

posted @ 2017-03-09 13:03  BOSON+CODE  阅读(659)  评论(0编辑  收藏  举报