• POJ 1185 状态DP


    这个题目是个挺难表示的状态DP,因为不但要考虑上下还要考虑左右,在DP里面就没有什么下了咯,但也至少除了考虑左右还要考虑上

    所以先枚举出在同一行满足条件的状态 即 某状态 若 s&(s<<1) 或者(s&(s<<2)) 则说明同一行的炮塔在射击范围内,要去掉。

    然后就是考虑不同行的了,只要上一行和上上行的状态不冲突即可

    于是就有了如下状态 

    dp[i][j][k]代表第i行状态为k,上一行的状态为j时的最大值。

    于是它的子状态就是 dp[i-1][w][j]代表上一行的状态为j 上上行的状态为w的最大值。

    于是 dp[i][j][k]=max(dp[i][j][k],dp[i-1][w][j]+calc[k]) (calc代表某个状态中1的个数 即炮塔的数目)。

    需要枚举四层循环 中间通过状态的对比来去掉一些没用的状态。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 11
    using namespace std;
    int dp[105][1<<N-3][1<<N-3];
    int A[105],m,n,calc[1<<N],num,state[1<<N];
    void init()
    {
        num=0;
        for (int i=0;i<(1<<m);i++)
        {
            int tmp=0;
            if (i&(i<<1) || i&(i<<2)) continue; //左右有冲突 跳过。
            state[num]=i;
            for (int j=0;j<m;j++)
            {
               if ((1<<j)&i)
                    tmp++;
            }
            calc[num++]=tmp; //算出某个状态中的含1的个数
        }
    }
    bool fit(int a,int b)//判断上下某个状态是否冲突
    {
        if (a&b) return 0;
        return 1;
    }
    void DP()
    {
        int ans=0;
        for (int i=0;i<num;i++) //先预处理第一行的情况
        {
            if (!fit(state[i],A[1]))
                continue;
            dp[1][0][i]=calc[i];
            ans=max(ans,dp[1][0][i]);
        }
        for (int i=2;i<=n;i++)
        {
            for (int k=0;k<num;k++) //这里的是先枚举k还是j 没什么大关系,两个状态彼此独立。
            {
                for (int j=0;j<num;j++)
                {
                    if (!fit(state[j],state[k])|| !fit(state[k],A[i]) || !fit(state[j],A[i-1]))//有冲突就直接跳过
                        continue;
                    for (int w=0;w<num;w++)
                    {
                        if (!fit(state[j],state[w])|| !fit(state[k],state[w]))
                            continue;
                        if (!fit(state[w],A[i-2])) continue;
                        dp[i][j][k]=max(dp[i][j][k],dp[i-1][w][j]+calc[k]);
                        ans=max(ans,dp[i][j][k]);
                    }
                }
            }
        }
        printf("%d
    ",ans);
    }
    int main()
    {
        char c;
    
        while (scanf("%d%d",&n,&m)!=EOF)
        {
            init();
            memset(dp,0,sizeof dp);
            for (int i=1;i<=n;i++)
            {
                getchar();
                A[i]=0;
                for (int j=0;j<m;j++)
                {
                    c=getchar();
                    if (c=='H')
                        A[i]+=1<<j; //这里故意把H设置为1,是为了正好用上面的fit函数,如果有状态把炮塔建在H上,就是不可取的状态。
                   // cout<<c;
                }
               // cout<<endl;
            }
            DP();
    
        }
        return 0;
    }
  • 相关阅读:
    紫书 例题8-18 UVa 1442 (扫描法)
    紫书 例题8-17 UVa 1609 (构造法)(详细注释)
    紫书 例题8-16 UVa 1608 (递归)
    紫书 例题8-15 UVa 12174 (滑动窗口)
    紫书 例题8-14 UVa 1607 (二分)
    紫书 例题8-13 UVa 11093 (反证法)
    紫书 例题8-12 UVa 12627 (找规律 + 递归)
    Codeforces Round #441 (Div. 2, by Moscow Team Olympiad)
    CodeForces
    CodeForces 444C 线段树
  • 原文地址:https://www.cnblogs.com/kkrisen/p/3606168.html
Copyright © 2020-2023  润新知