[状态压缩DP] Poj 3254, Poj 1185
2012-07-23 11:45
387 查看
状态压缩DP一般适合的题型的特征为:一个矩阵,行数较大,列数较小,每个点的状态只有两种。正好用一个整型数int来表示每行的一种状态(其实是其二进制形式,每bit的0和1表示每点的状态)。不同的是各题的状态dp的定义,状态间的限制,状态的转换方程。
第一道(Poj 3254):
第二道(Poj 1185):
第一道(Poj 3254):
/** 题意:在一片M行N列的草地上(用0和1矩阵表示),1表示能放牛,0表示不能放。 在草地上放牛并且牛不能相邻,问有多少种放法(一头牛都不放也算一种)。 题解:对于每一行来说,放牛的可能数有2^N种,但是根据以下限制条件就能排除很多: 1.每行中的牛不能相邻,经计算当N=12时,满足条件的状态只有377个 2.每行中放牛要满足草地的硬件条件,只有1处可放,排除一些 3.上一行中与本行对应的位置处不能放牛,排除一些 由于N值最大为12,所以可以用一个二进制数来表示一行的状态,这就是“状态压缩”了。 定义dp[i][j]:第i行的状态为state[j]时,前i行能放牛方法的总数. */ #include <cstdio> #include <queue> #include <algorithm> #include <iostream> #include <cstring> using namespace std; #define MOD 100000000 int n, m, row[12]; int nState, state[1000]; int dp[14][1000]; void init() { int k = 1 << n; nState = 0; for (int i = 0; i < k; i++) if ( (i & (i<<1)) == 0 ) state[nState++] = i; } int main() { int k; scanf("%d %d", &m, &n); init(); for (int i = 0; i < m; i++) { row[i] = 0; for (int j = n-1; j >= 0; j--) { scanf("%d", &k); row[i] += k << j; } } // 求dp[0],若state[j]满足第0行草地的硬件条件,则dp[0][j]=1 for (int j = 0; j < nState; j++) { dp[0][j] = ( (row[0] & state[j]) == state[j] ) ? 1 : 0; } // 求dp[i],如果state[j]和第i-1行的状态state[k]不冲突,则dp[i][j]=Σ(dp[i-1][k]) for (int i = 1; i < m; i++) { for (int j = 0; j < nState; j++) { if ( (row[i] & state[j]) != state[j] ) //判断是否满足草地硬件条件 continue; for (int k = 0; k < nState; k++) { if ( dp[i-1][k] && (state[k]&state[j]) == 0 ) dp[i][j] = (dp[i][j] + dp[i-1][k]) % MOD; } } } int res = 0; for (int j = 0; j < nState; j++) { if ( dp[m-1][j] ) res = (res + dp[m-1][j]) % MOD; } printf("%d\n", res); return 0; }
第二道(Poj 1185):
/** 题意:在一个n行m列的矩阵中,字符'P'处能放炮兵,字符'H'处不能放炮兵。 并且如果两个炮兵在一条(水平或垂直)直线上时,它们的距离不能小于2,问最多放多少个兵。 由于在求第i行时,它的状态要收到第i-1行和i-2行的影响,所以定义一个三维dp: dp[i][j][k]表示第i行的状态为state[j],第i-1行的状态为state[k]时,前i行能放炮兵的最大数量。 for ( ... i < n ...) { for ( ... j < nState ... ) { 如果状态j和第i行的地形不冲突,那么: for ( ... k < nState ... ) { 如果第i行状态j和第i-1行状态k不冲突,那么: for ( ... h < nState ... ) { 如果第i行状态j和第i-2行状态h不冲突,那么: 在dp[i-1][k][h]中找最大的一个赋值给dp[i][j][k],再加上state[j]中1的个数 } } } } */ #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int n, m, dp[105][80][80]; //dp[i][j][k]表示第i行的状态为j,第i-1行的状态为k时能放炮兵的最大数量 int nState, state[80], num[80]; //10位二进制位中各个1之间的距离不小于2,这样的数只有60个。 //依次存放在state[]中,num[i]表示state[i]中1的个数 //在小于2^m的数中找1之间的距离不小于2的数,保存在state[]中 void init() { int k = 1 << m; nState = 0; for (int i = 0; i < k; i++) if ( (i&(i<<1)) == 0 && (i&(i<<2)) == 0 ) { state[nState] = i; num[nState] = 0; int j = i; while (j) { num[nState] += j % 2; j /= 2; } nState++; } } int main() { int row[105]; char str[15]; while ( cin >> n >> m ) { init(); for (int i = 0; i < n; i++) { row[i] = 0; scanf("%s", str); for (int j = 0; j < m; j++) if (str[j] == 'P') row[i] += 1 << j; } memset(dp, 0, sizeof(dp)); // 计算dp[0] for (int j = 0; j < nState; j++) { if ( (state[j] & row[0]) != state[j] ) continue; for (int k = 0; k < nState; k++) dp[0][j][k] = num[j]; } // 计算dp[1] if (n > 1) for (int j = 0; j < nState; j++) { if ( (state[j] & row[1]) != state[j] ) continue; for (int k = 0; k < nState; k++) { if ( (state[j] & state[k]) == 0 ) dp[1][j][k] = dp[0][k][0] + num[j]; } } // 计算dp[>1] for (int i = 2; i < n; i++) { for (int j = 0; j < nState; j++) { if ( (state[j] & row[i]) != state[j] ) continue; for (int k = 0; k < nState; k++) { if ( state[j] & state[k] ) continue; for (int h = 0; h < nState; h++) { if ( state[j] & state[h] ) continue; if ( dp[i-1][k][h] > dp[i][j][k] ) dp[i][j][k] = dp[i-1][k][h]; } dp[i][j][k] += num[j]; } } } // 在dp[n-1]中找最大值 int max = 0; for (int j = 0; j < nState; j++) { for (int k = 0; k < nState; k++) if (max < dp[n-1][j][k]) max = dp[n-1][j][k]; } printf("%d\n", max); } }---------------------- 更多“状态压缩DP”题目... ------------------------
相关文章推荐
- POJ 3254 & POJ 1185 (状态压缩DP)
- 状态压缩DP (poj 3254, poj 1185, nyoj 81)
- 状态压缩DP 入门 POJ 3254
- POJ 1185 状态压缩DP(转)
- poj 3254 corn fields (状态压缩dp~)
- poj 1185 炮兵阵地 状态压缩dp
- POJ 3254 【状态压缩DP】
- poj 3254 Corn Fields_状态压缩dp
- poj 3254(状态压缩dp)
- poj 3254 Corn Fields (状态压缩dp)
- poj 3254 Corn Fields (状态压缩DP)
- POJ 3254 Corn Fields (状态压缩DP)
- POJ 3254 Corn Fields 状态压缩DP
- poj 1185 炮兵阵地 [经典状态压缩DP]
- 【状态压缩DP】POJ 1185
- 状态压缩DP总结【POJ3254】【POJ1185】【POJ3311】【HDU3001】【POJ2288】【ZOJ4257】【POJ2411】【HDU3681】
- poj 1185 炮兵阵地 (状态压缩 dp)
- [状态压缩DP] POJ 1185
- 状态压缩DP总结【POJ3254】【POJ1185】【POJ3311】【HDU3001】【POJ2288】【ZOJ4257】【POJ2411】【HDU3681】
- poj 1185 炮兵阵地 状态压缩dp