Why so serious? --[NKU]schindlerlee

2010年1月13日星期三.pku1185 状态压缩动态规划

2010年1月13日星期三.pku1185
状态压缩动态规划

pku1185:题目是中文的,而且题目很经典,题意不再赘述。

这个题目比pku2411和sgu131两题来说多了一行状态需要储存
因为如果上上行和此行有关
而且此题不再是求完美覆盖的方式,而是求能最大的放置个数。

方法是先求出一行中的所有放置方法。
然后逐行递推,然后在递推的过程中枚举当前行状态,如果和上两行不冲突的话,就
进行放置个数的更新

f[N][60][60] //N行,上一行的状态号,上上行的状态号

具体看代码吧
  1 
  2 /*
  3  * SOUR:pku1185
  4  * ALGO:State Compression DP
  5  * DATE: 2010年 01月 13日 星期三 13:57:49 CST
  6  * COMM:4 http://www.cppblog.com/schindlerlee
  7  * */
  8 #include<iostream>
  9 #include<cstdio>
 10 #include<cstdlib>
 11 #include<cstring>
 12 #include<algorithm>
 13 using namespace std;
 14 typedef long long LL;
 15 const int maxint = 0x7fffffff;
 16 const long long max64 = 0x7fffffffffffffffll;
 17 
 18 #define bin(i) (1 << (i))
 19 #define low(i) ((i) & -(i))
 20 #define SL(i) ((i) << 1)
 21 #define SR(i) ((i) >> 1)
 22 
 23 void ckmax(int &a, int b)
 24 if (a < b) a = b; }
 25 
 26 const int N = 102;
 27 const int M = 10;
 28 
 29 //60是对M==10的一行进行深搜得到的最大状态数量
 30 int f[N][60][60], n, m, terrain[N], full;
 31 int s[60], top, c[60];
 32 
 33 int legal(int x)
 34 {
 35     int b = 0, cnt = 0, c;
 36     while (x > 0) {
 37         cnt++;
 38         c = low(x);
 39         if (SL(b) & x || SL(SL(b)) & x) {
 40             return -1;
 41         }
 42         x ^= c;
 43         b = c;
 44     }
 45     return cnt;
 46 }
 47 
 48 void preprocess()
 49 {
 50     int i, j, cnt;
 51     for (i = 0; i <= full; i++) {
 52         if ((cnt = legal(i)) >= 0) {
 53             s[top] = i, c[top] = cnt, top++;
 54         }
 55     }
 56 }
 57 
 58 bool contradict(int cur, int s1, int s2)
 59 return (cur & s1) || (cur & s2); }
 60 
 61 int main()
 62 {
 63     int i, j, k;
 64     char str[12];
 65     while (scanf("%d%d\n"&n, &m) == 2) {
 66         full = bin(m) - 1;
 67         preprocess();
 68 
 69         for (i = 1; i <= n; i++) {
 70             scanf("%s\n", str);
 71             int tmp = 0;
 72             for (j = 0; j < m; j++) {
 73                 tmp <<= 1;
 74                 if (str[j] == 'H') {
 75                     tmp |= 1;
 76                 }
 77             }
 78             terrain[i] = tmp;
 79         }
 80 
 81         for (i = 1; i <= n; i++) {
 82             for (j = 0; j < top; j++) { //枚举当前行
 83                 int cur = s[j], curcnt = c[j];
 84                 if (cur & terrain[i]) {
 85                     continue;
 86                 }    //不符合第i行地形要求
 87 
 88                 for (int k1 = 0; k1 < top; k1++) { //枚举前两行
 89                     for (int k2 = 0; k2 < top; k2++) {
 90                         if (!contradict(cur, s[k1], s[k2])) { //和上两行状态不冲突
 91                             ckmax(f[i][j][k1], f[i - 1][k1][k2] + curcnt);
 92                         }
 93                     }
 94                 }
 95             }
 96         }
 97 
 98         int res = 0;
 99         for (i = 0; i < top; i++) {
100             for (j = 0; j < top; j++) {
101                 ckmax(res, f[n][i][j]);
102             }
103         }
104         printf("%d\n", res);
105     }
106     return 0;
107 }
108 
109 


posted on 2010-01-13 22:25 schindlerlee 阅读(1045) 评论(0)  编辑 收藏 引用 所属分类: 解题报告


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理