poj1185 炮兵阵地(状态压缩dp)

来源:互联网 发布:合肥软件开发 编辑:程序博客网 时间:2024/06/05 07:18

这题。。。换成3维后,果断更不好做了啊


首先说说为什么换成三维,dp数组有个特点,由前一个状态才能得到下一个状态,这样做的前提就是必须要保存前面状态的下标,而这个要兼顾前两行状态,所以由二维变为三维。变为三维后,就有个建模的过程。三维建模有两种,假设高为h,一种是直接立方体,另一种是h个矩形,这个题还是用立方体想比较好。


然后是数组的大小,这里有人说top为60,这个60怎么来的呢?二进制数一共10位,总共2^10 - 1,但其实一行最多放4个炮,所以就开始分类:

0个炮:1种;

1个炮:10种;

2个炮:?

3个炮:?

4个炮:1种。

重点是2和3个炮,(例如2个)这相当于先求当4对炮相邻有多少种方法,然后在乘C(2上, 5下)(不会插数学符号T T。。。)。3个炮也是类似,然而我现在不会求了,数学渣T T,所以只能留白了,以后复习了概率论再算吧。。。


再次是求动态方程。上一题玉米是求方案数,这一题是求最多放炮数,所以最后不需要累加,只是求最值就好(其实最大值也往往在数组下面)。

动态方程:dp[i][k][t] = max(dp[i][k][t], dp[i - 1][j][k] + num[t])。

注意t代表当前行,k代表上一行,j代表上上行,这样就好理解了。每次判断前的剪枝不要忘掉。


对了还有个位运算x &= (x - 1);统计1的个数,也比较经典,记住就好了。


说白了,这两道状压要在理解加记忆的基础上才能A掉,特别是这种长代码,哎,只能多做题加深印象了,总不能死记吧。。。

#include <stdio.h>#include <algorithm>#include <string.h>#include <iostream>using namespace std;const int N = 60;const int INF = 1e8;const int mod = 100000000;int n, m, top, total;int state[N], cur[105], dp[105][N][N], num[N];bool ok(int x){    if(x & (x << 1)) return false;    if(x & (x << 2)) return false;    else return true;}void init(){    top = 0;    total = 1 << m;    for(int i = 0; i < total; i ++)    {        if(ok(i)) state[++ top] = i;    }}bool fit(int x, int y){    if(x & y) return false;    else return true;}int jcount(int x){    int cnt = 0;    while(x)    {        cnt ++;        x &= (x - 1);    }    return cnt;}int main(){  //  freopen("in.txt", "r", stdin);    char c;    while(~scanf("%d%d", &n, &m))    {        memset(dp, -1, sizeof(dp));        init();        //输入,同时记录该行的状态        for(int i = 1; i <= n; i ++)        {            cur[i] = 0;            for(int j = 1; j <= m; j ++)            {                cin >> c;                if(c == 'H') cur[i] += (1 << (m - j));            }        }        //初始化第一行        for(int i = 1; i <= top; i ++)        {            num[i] = jcount(state[i]);            if(fit(state[i], cur[1])) dp[1][1][i] = num[i];        }        //分层dp        for(int i = 2; i <= n; i ++)        {            for(int t = 1; t <= top; t ++)//当前行            {                if(!fit(state[t], cur[i])) continue;                for(int j = 1; j <= top; j ++)//上上行                {                    if(!fit(state[j], cur[i - 2])) continue;                    if(state[t] & state[j]) continue;                    for(int k = 1; k <= top; k ++) //上一行                    {                        if(!fit(state[k], cur[i - 1])) continue;                        if(state[t] & state[k]) continue;                        if(dp[i - 1][j][k] == -1) continue;                        dp[i][k][t] = max(dp[i][k][t], dp[i - 1][j][k] + num[t]);                    }                }            }        }        //输出        int ans = 0;        for(int i = 1; i <= n; i ++)            for(int j = 1; j <= top; j ++)                for(int k = 1; k <= top; k ++)                    ans = max(ans, dp[i][j][k]);        printf("%d\n", ans);    }    return 0;}


0 0
原创粉丝点击