• 《算法竞赛进阶指南》0x56状态压缩DP POJ1185


    题目链接:http://poj.org/problem?id=1185

    给定一个n*m的矩阵,每个点可能是山也可能是平地,在上面放士兵,只能放在平地上,每个点上下左右两格为攻击范围,士兵之间的攻击范围不能覆盖中心点,问最多可以放多少个士兵。

    解决方案:一行的状态由前面两行决定,如果用01表示不放和放的话,那么状态就是前i行,第i-1行状态是j,第i行的状态是k,第i阶段只和第i-1阶段的有关系

    可以处理出行内的合法状态,并保存在集合S中,三行之间放的应该没有交集,并且第i行不能放在山上,所以要判断,然后枚举三行的状态即可。

    最后对第n层的情况下进行枚举,或者计算到n+2层,并且n+2层和n+1层的都是0,表示最后两层都不放,前n+2层能放的最大的数量。

    代码;

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    using namespace std;
    const int N = 110,M=10,S=1<<M;
    int f[2][S][S];
    int n,m;
    int g[N];
    vector<int> state;
    int cnt[S];//状态中1的数量 
    bool check(int s){
        for(int i=0;i<m;i++)//为1的一位后面两位都要是0才正确 
            if((s>>i & 1) && ((s>>i+1 & 1) || (s>>i+2 & 1)))
                return false;
        return true;
    }
    int count(int s){
        int cnt=0;
        while(s){
            cnt+=s&1;
            s>>=1;
        }
        return cnt;
    }
    int main(){
        cin>>n>>m;
        for(int i=1;i<=n;i++)
            for(int j=0;j<m;j++){
                char c;
                cin>>c;
                if(c=='H')g[i]+=1<<j;
            }
        
        for(int i=0;i<1<<m;i++){
            if(check(i)){//查看i状态是否满足行内1之间距离大于等于2 
                state.push_back(i);
                cnt[i]=count(i); 
            }
        }
        
        f[1][0][0]=0; 
        for(int i=1;i<=n;i++){
            for(int j=0;j<state.size();j++)
                for(int k=0;k<state.size();k++)
                    for(int u=0;u<state.size();u++){
                        int a=state[u],b=state[j],c=state[k];
                        if((a&b) || (a&c) || (b&c))continue;//状态存在交集 
                        if(c & g[i])continue;//第i行没放在山上 
                        f[i & 1][j][k]=max(f[i & 1][j][k],f[i-1 & 1][u][j]+cnt[c]); 
                    }
        }
        int ans=-0x3f3f3f3f;
        for(int i=0;i<state.size();i++)
            for(int j=0;j<state.size();j++){
                if(!(state[i] & state[j]))
                    ans=max(ans,f[n & 1][i][j]);
            }
            
        cout<<ans<<endl;
    }
  • 相关阅读:
    成功解决vc6.0智能提示消失的BUG
    如何在vc6,vc7,vc8下编译x264
    Visual C++ 操作MS Offfice 控件
    在英文版Visual Studion 2005 professional 中使用 Windows Mobile 2003 SE中文模拟器
    x264 20060731 svn 版的编码移植
    泛型算法:Tips
    05年度EmilMatthew’s Blog文档整理
    常用软件滤波方法及其示例程序
    windows server 2003 配置
    TI C64X 视频处理应用编程重点内容提示
  • 原文地址:https://www.cnblogs.com/randy-lo/p/13413803.html
Copyright © 2020-2023  润新知