zoukankan      html  css  js  c++  java
  • 状态压缩DP棋盘模型总结

    论文:《周伟ftfish --- 动态规划之状态压缩》 关键之处在于: ①针对棋盘不同限制用dfs把每行可行的状态压缩表示成一个数存到s[]。 ②枚举当前处理行和上一行的状态时根据题目限制判断状态是否互斥。 ③有时棋盘上会有些点不能放置,我们也把一行中不能放置的点压缩成一个数存到no[]中,比如用00011000表示第3列和第4列不能放置。然后处理当前行时如果s[j1] & no[i] == 0表示当前放置情况与不能放置的点不冲突。   sgu 223 Little Kings  棋盘限制:在n*n(n<=10)的棋盘上放k个国王(可攻击相邻的8个格子,不能放其他国王),求方案数。 分析:当前行的状态矛盾只涉及到上一行,并且还有放几个国王的限制,所以设dp[i][j][k]表示处理到第i行,第i行状态为j放了k个国王的方案数 dp[i][j][k] = dp[i-1][j'][k-c[j']].  
    //sgu 223 状态压缩DP 棋盘
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #define MID(x,y) ((x+y)>>1)
    #define mem(a,b) memset(a,b,sizeof(a))
    using namespace std;
    
    typedef long long LL;
    const int sup = 0x7fffffff;
    const int inf = -0x7fffffff;
    
    int n, k;
    const int NUM_OF_PLACEMENGT = 520;
    int s[NUM_OF_PLACEMENGT], c[NUM_OF_PLACEMENGT], place_num;         //the placement of each line
    long long dp[13][NUM_OF_PLACEMENGT][103];
    
    void dfs(int p, int condition_num, int condition_one_amount){             //Store the placement of each line
        if (p == n){
            s[++ place_num] = condition_num;
            //cout << place_num << " " << s[place_num] << endl;
            c[place_num] = condition_one_amount;
            return ;
        }
        dfs(p+1, condition_num << 1, condition_one_amount);
        if (!(condition_num & 1))
            dfs(p+1, condition_num << 1 | 1, condition_one_amount + 1);
        return ;
    }
    bool ifok(int s1, int s2){      //decide whether tha current condition and the last condition are comtradictry.
        if(s1 & s2) return false;         //和正上方判断
        if(s1 & (s2<<1))return false;     //和右上方判断
        if(s1 & (s2>>1))return false;     //和左上方判断
        return true;
    }
    int main(){
        while(scanf("%d %d", &n, &k) != EOF){
            //cout << n << " " << k << endl;
            mem(dp, 0);
            place_num = 0;
            dp[0][1][0] = 1;
            dfs(0, 0, 0);
            for (int i = 1; i <= n; i ++){
                for (int j1 = 1; j1 <= place_num; j1 ++){
                    for (int j2 = 1; j2 <= place_num; j2 ++){
                        for (int w = 0; w <= k; w ++){
                            if (ifok(s[j1], s[j2]) && w-c[j1] >= 0)
                                dp[i][j1][w] += dp[i-1][j2][w-c[j1]];
                        }
                    }
                }
            }
            long long res = 0;
            for (int j = 1; j <= place_num; j ++)
                res += dp[n][j][k];
            printf("%I64d\n", res);
        }
    	return 0;
    }
    
      hdu 4539 郑厂长系列故事——排兵布阵 棋盘限制:在n*m(n<=100, m<=10)的棋盘上放士兵,每个士兵的曼哈顿距离2的地方都不能放别的士兵。并且有些地方不能放士兵。求最多能放几个士兵。 分析:因为距离为2可能涉及到上2行的状态,所以设dp[i][j1][j2]表示处理到第i行,第i行状态为j1,第i-1行状态为j2最多能放几个士兵。然后因为某些地方不能放置,需要用到③的s[j1] & no[i]。dp[i][j1][j2] = max(dp[i][j1][j2], dp[i-1][j2][j3])  
    //HDU 4539 状态压缩DP 棋盘
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #define MID(x,y) ((x+y)>>1)
    #define mem(a,b) memset(a,b,sizeof(a))
    using namespace std;
    
    typedef long long LL;
    const int sup = 0x7fffffff;
    const int inf = -0x7fffffff;
    
    int n, m;
    const int NUM_OF_PLACEMENGT = 500;
    int s[NUM_OF_PLACEMENGT], c[NUM_OF_PLACEMENGT], place_num;         //the placement of each line
    int dp[2][NUM_OF_PLACEMENGT][NUM_OF_PLACEMENGT];
    vector  dd[NUM_OF_PLACEMENGT];
    int no[105];
    
    void dfs(int p, int condition_num, int condition_one_amount){             //Store the placement of each line
        if (p == m){
            s[++ place_num] = condition_num;
            //cout << condition_num << endl;
            c[place_num] = condition_one_amount;
            return ;
        }
        dfs(p+1, condition_num << 1, condition_one_amount);
        if (!(condition_num & 2))
            dfs(p+1, condition_num << 1 | 1, condition_one_amount + 1);
        return ;
    }
    bool ifok(int s1, int s2){      //decide whether tha current condition and the last condition are comtradictry.
        //if(s1 & s3)     return false;         //和正上方判断
        if(s1 & (s2<<1))    return false;     //和右上方判断
        if(s1 & (s2>>1))    return false;     //和左上方判断
        return true;
    }
    int main(){
        while(scanf("%d %d", &n, &m) == 2){
            mem(no, 0);
            place_num = 0;
            mem(dp, -1);
            dp[0][1][1] = 0;
            dfs(0, 0, 0);
            for (int i = 1; i <= n; i ++)
            for (int j = 1; j <= m; j ++){
                int tmp;
                scanf("%d", &tmp);
                if (tmp == 0)   no[i] += (1 << (m-j));
            }
            for (int i = 1; i <= n; i ++)
                for (int j1 = 1; j1 <= place_num; j1 ++){
                    if(s[j1] & no[i])   continue;
                    for (int j3 = 1; j3 <= place_num; j3 ++){
                        if (s[j1] & s[j3])  continue;
                        for (int j2 = 1; j2 <= place_num; j2 ++){
                            if (ifok(s[j1],s[j2]) && dp[(i-1)&1][j2][j3] != -1){
                                dp[i&1][j1][j2] = max(dp[i&1][j1][j2], dp[(i-1)&1][j2][j3] + c[j1]);;
                            }
                        }
                    }
                }
            int res = 0;
            for (int j1 = 1; j1 <= place_num; j1 ++)
                for (int j2 = 1; j2 <= place_num; j2 ++)
                    res = max(res, dp[n&1][j1][j2]);
            printf("%d\n", res);
        }
        return 0;
    }
    
      poj 1185 炮兵阵地 棋盘限制:在n*m(n<=100, m<=10)的棋盘上放士兵,每个士兵上下左右2格子内都不能放别的士兵。并且有些地方不能放士兵。求最多能放几个士兵。 分析:和上一题基本一样,就是判断状态互斥时有区别。  
    //POJ 1185 炮兵阵地 状态压缩DP
    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #define MID(x,y) ((x+y)>>1)
    #define mem(a,b) memset(a,b,sizeof(a))
    using namespace std;
    
    typedef long long LL;
    const int sup = 0x7fffffff;
    const int inf = -0x7fffffff;
    
    int n, m;
    int no[104];
    int dp[104][300][300];
    vector  s,c;
    void dfs(int p, int condition_num, int condition_amount){
        if (p == m){
            s.push_back(condition_num);
            c.push_back(condition_amount);
            //cout << condition_num << endl;
            return;
        }
        dfs(p + 1, condition_num << 1, condition_amount);
        if ((condition_num & 3) == 0)
            dfs(p + 1, condition_num << 1 | 1, condition_amount + 1);
        return ;
    }
    
    int main(){
        scanf("%d %d", &n, &m);
        mem(no, 0);
        for (int i = 1; i <= n; i ++)
            for (int j = 1; j <= m; j ++){
                char c_tmp;
                cin >> c_tmp;
                if (c_tmp == 'H')
                    no[i] += (1 << (m - j));
            }
        mem(dp, -1);
        dp[0][0][0] = 0;
        dfs(0, 0, 0);
        for (int i = 1; i <= n; i++){
            for (int j1 = 0; j1 < (int)s.size(); j1 ++){
                if (s[j1] & no[i])          //不能在H处
                    continue;
                for (int j2 = 0; j2 < (int)s.size(); j2 ++){
                    if (s[j1] & s[j2])      //上面一格
                        continue;
                    for (int j3 = 0; j3 < (int)s.size(); j3 ++){
                        if (s[j1] & s[j3])      //上面两格
                            continue;
                        if (dp[i-1][j2][j3] != -1){
                            dp[i][j1][j2] = max(dp[i][j1][j2], dp[i-1][j2][j3] + c[j1]);
                        }
                    }
                }
            }
        }
        int res = 0;
        for (int j1 = 0; j1 < (int)s.size(); j1 ++){
            for (int j2 = 0; j2 < (int)s.size(); j2 ++){
                res = max(res, dp[n][j1][j2]);
            }
        }
        printf("%d\n", res);
    	return 0;
    }
    
     
    举杯独醉,饮罢飞雪,茫然又一年岁。 ------AbandonZHANG
  • 相关阅读:
    微人事项目-mybatis-持久层
    通过外键连接多个表
    springioc
    Redis 消息中间件 ServiceStack.Redis 轻量级
    深度数据对接 链接服务器 数据传输
    sqlserver 抓取所有执行语句 SQL语句分析 死锁 抓取
    sqlserver 索引优化 CPU占用过高 执行分析 服务器检查
    sql server 远程备份 bak 删除
    冒泡排序
    多线程 异步 beginInvoke EndInvoke 使用
  • 原文地址:https://www.cnblogs.com/AbandonZHANG/p/4114013.html
Copyright © 2011-2022 走看看