POJ 1185 炮兵阵地

  • 阿里云国际版折扣https://www.yundadi.com

  • 阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

    感觉上很难,确实自己做一开始没有想到是dp问题,同时没有进行剪枝,同时有一些准备工作没有做好

    • 没有提前将每一行的信息转成数字信息(做题经验不足)
    • 没有提前把每行可能的情况抽取出来
    • 没有想到其实确实是一个dp问题(其实一开始的贪心思路有些不太对)

    判断贪心和dp问题的一个方法可以是看数据范围

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    int dp[105][65][65];
    int cnt=0;
    int str[65];
    int sum[65];
    int map[110];
    char s[110][110];
    bool check(int x)//判断这个排列是否为普通的合法序列
    {
        if(x&(x<<1)) return false;
        if(x&(x<<2)) return false;
        return true;
    }
    int getSum(int x)//当前状态的炮兵数目
    {
        int ans=0;
        while(x>0)
        {
            if(x&1) ans++;
            x>>=1;
        }
        return ans;
    }
    void before_hand(int mid)//预处理出所有的可能合法炮兵状态,cnt统计状态数
    {
        for(int i=0;i<(1<<mid);i++)
        {
            if(check(i))
            {
                str[cnt]=i;//str数组记录状态,dp中的j和k都是str数组的下标
                sum[cnt]=getSum(i);
                cnt++;
            }
        }
    }
    int main()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        memset(dp,-1,sizeof dp);
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                char a;
                cin >> a;
                if(a=='H') map[i]|=(1<<j);//统计每一行的不合法格子状态
            }
        }
        before_hand(m);//其实可以不传参
        for(int i=0;i<cnt;i++)
        {
            if(!(str[i]&map[0])) dp[0][0][i]=sum[i];//先处理出第一行的情况
        }
        for(int r=1;r<n;r++)//枚举行数
        {
            for(int i=0;i<cnt;i++)//枚举当前行的排列
            {
                if(str[i]&map[r]) continue;
                for(int j=0;j<cnt;j++)//枚举上一行的排列情况
                {
                    if(str[i]&str[j]) continue;
                    for(int k=0;k<cnt;k++)//枚举i-2行的排列情况
                    {
                        if(str[i]&str[k]) continue;
                        if(dp[r-1][k][j]==-1) continue;
                        dp[r][j][i]=max(dp[r][j][i],dp[r-1][k][j]+sum[i]);//更新即可
                    }
                }
            }
        }
        int ans=0;//统计答案
        for(int i=0;i<cnt;i++)
        {
            for(int j=0;j<cnt;j++)
            {
                ans=max(ans,dp[n-1][i][j]);
            }
        }
        printf("%d\n",ans);
        return 0;
    }

     

  • 阿里云国际版折扣https://www.yundadi.com

  • 阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6