zoukankan      html  css  js  c++  java
  • POJ 1185 状态压缩DP 炮兵阵地

    题目直达车:   POJ 1185 炮兵阵地

    分析:

    列( <=10 )的数据比较小, 一般会想到状压DP.

    Ⅰ、如果一行10全个‘P’,满足题意的状态不超过60种(可手动枚举)。

    Ⅱ、用DFS搜出所有可能表示状态的整数(二进制1表示可以放,0则不能)。

    Ⅲ、对每一行的地行进行状态处理(p[i]表示第i行地形的状态),二进制‘H’转1,‘P’转0;

    Ⅳ、用dp[i][j][k]表示第i行,且i行状态为j,i-1行状态为k时,最多能放置的量。

    Ⅴ、对于第i行的可行状态必须满足:

                   ⒈  j & k =0 且 j & t =0 (t为第i-2行放置状态)与前两行匹配,即不互相攻击。

                   ⒉  j & p[i] = 0 与地形匹配,即只放平原地带。

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

          (num[j]为第j种状态中放置炮兵的数量)   

    第一次做状态DP,  参考(题解报告)的思路才敲出来

    代码: 

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<vector>
    using namespace std;
    int p[105],dp[105][65][65];
    vector<int>M[11];
    int a[11],n,m;
    void DFS(int k,int t){  ///搜索m=t时如果全为'P'可以表示状态的整数
        if(k==t){
            int p=0;
            for(int i=0;i<t;++i)
                if(a[i]) p=p|(1<<i);
            M[t].push_back(p);  /// 记下能表示状态的整数
            return;
        }
        for(int i=0;i<=1;++i){ 
            if(i&&((k&&a[k-1])||(k>1&&(a[k-1]||a[k-2])))) continue;
            a[k]=i;
            DFS(k+1,t);
        }
    }
    int main(){  
        for(int i=1;i<=10;++i) DFS(0,i); 
        while(~scanf("%d%d",&n,&m)&&n+m){
            p[0]=0; 
            ///num[i]记下用第i种状态(整数M[m][i]表示) 中设了多少炮兵部队
            int num[65], len=M[m].size();
            for(int i=0;i<len;++i)
                num[i]=__builtin_popcount( M[m][i] ); ///计算M[m][i]中二进制中1的个数 
            memset(dp,0,sizeof(dp));
            int Max=0;
            for(int i=1;i<=n;++i){
                char ch[105]; scanf("%s",ch);
                p[i]=0;
                //预处理地形(1代表'H',0代表'P')
                for(int j=0;j<m;++j) if(ch[j]=='H') p[i]|=(1<<j);
                if(i==1){ //初始化第一行所有布置情况
                    for(int k=0; k<len; ++k)
                        for(int j=0; j<len; ++j){
                            if(!(M[m][k]&p[1])) dp[1][k][j]=num[k];
                            else dp[1][k][j]=0;
                            Max=max(Max,dp[1][k][j]);
                        }
                    continue;
                }
                for(int j=0; j<len; ++j)//当前行
                    if(!(M[m][j]&p[i])) //与 地形匹配
                        for(int k=0; k<len; ++k)//i-1
                            if(!(M[m][k]&p[i-1])&&!(M[m][k]&M[m][j]))//与 地形、i-1行匹配
                                for(int t=0; t<len; ++t)//i-2
                                    //与 地形、i-1行、i-2行匹配
                                    if(!(M[m][t]&p[i-2])&&!(M[m][t]&M[m][k])&&!(M[m][t]&M[m][j])){ 
                                        dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][t]+num[j]);
                                        if(i==n)Max=max(dp[i][j][k],Max);
                                    }           
            }
            printf("%d
    ",Max);
        }
        return 0;
    }
    
    



  • 相关阅读:
    SpringBoot项目设置maven打包时间
    SpringBoot热部署配置
    Git笔记
    SpringBoot LogBack日志配置
    CURL使用教程
    Linux 安装Docker及使用
    转发和重定向的区别
    16周作业
    16
    15周
  • 原文地址:https://www.cnblogs.com/pangblog/p/3253897.html
Copyright © 2011-2022 走看看