• POJ1185:炮兵阵地(状压dp)


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

    大神的题解:

    方法就是用DP[i][r][p]表示第i行状态为r,第i-1行状态是p时的最多个数。而这里p受到r的限制,而第i-2行状态q则受到r和p两个状态限制。状态转移方程就是:

                 DP[i][r][p] = MAX{DP[i-1][p][q] +num[r]}

    其中,p是受到r的限制时枚举的状态,q是受到r和p共同限制时候的状态,num[r]表示状态r里面的布局炮兵所摆的个数。

    这里我们可以看到就要枚举i,r,p,q,这4 个变量,i的范围是100,而其他几个则都是1<<10,复杂度颇为偏高。而实际上由于每一行里面有很多都是某些位置被其他位置影响的。比如:   1110001,  如果第一个位置放上炮兵,那么第二第三的位置都会受到影响,而一个也放不了。

    解决方案就是不去管那些相互有影响的状态,把形如:

    1000000    0100000    ... ...

    1001000    0100001    ... ...

    ...

    1001001

    这些相互之间没有影响的状态找出来,这样所有的状态数就会减少至少于60种(我算了一下,好像是58种),这样一来就是60*60*60*100,可以过了。

    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <math.h>
    #define mod 100000000
    using namespace std;
    int m,n,top,state[110],cur[110],num[110],dp[110][110][110];
    char tu[110][20];
    inline bool ok(int x)
    {
        if(x&(x<<1)) return false;
        if(x&(x<<2)) return false;
        return true;
    }
    inline void init()
    {
        int tol=1<<n;
        top=0;
        for(int i=0; i<tol; i++)
        {
            if(ok(i)) state[++top]=i;
        }
    }
    inline bool fit(int x,int k)
    {
        if(x&cur[k]) return false;
        return true;
    }
    inline int icount(int x)
    {
        int cnt=0;
        while(x)
        {
            cnt++;
            x=x&(x-1);
        }
        return cnt;
    }
    int main()
    {
        while(scanf("%d%d",&m,&n)!=EOF)
        {
            init();
            for(int i=1; i<=m; i++)
                scanf("%s",tu[i]+1);
            for(int i=1;i<=m;i++)
            {
                cur[i]=0;
                for(int j=1;j<=n;j++)
                {
                    if(tu[i][j]=='H')
                        cur[i]+=(1<<(n-j));
                }
            }
            memset(dp,0,sizeof(dp));
            for(int i=1; i<=top; i++)
            {
                num[i]=icount(state[i]);
                if(fit(state[i],1))
                    dp[1][1][i]=num[i];
            }
            for(int i=2; i<=m; i++)
            {
                for(int t=1; t<=top; t++)
                {
                    if(!fit(state[t],i)) continue;//符合本行
                    for(int j=1; j<=top; j++)
                    {
                        if(state[j]&state[t]) continue;//符合上一行
                        for(int k=1; k<=top; k++) //符合上上行
                        {
                            if(state[k]&state[t]) continue;
                            if(state[k]&state[j]) continue;
                            dp[i][j][t]=max(dp[i][j][t],(dp[i-1][k][j]+num[t]));
                        }
                    }
                }
            }
            int maxx=-1;
            for(int i=1; i<=m; i++)
            {
                for(int j=1; j<=top; j++)
                {
                    for(int k=1; k<=top; k++)
                    {
                        maxx=max(maxx,dp[i][j][k]);
                    }
                }
            }
            printf("%d
    ",maxx);
        }
        return  0;
    }
  • 相关阅读:
    构造和析构
    const修饰的成员函数
    class和struct权限
    封装加强
    函数重载实现原理
    Unity2019破解hub
    Lua模拟stack
    函数重载
    LeanTween
    占位参数和默认参数
  • 原文地址:https://www.cnblogs.com/zhangmingcheng/p/4372712.html
Copyright © 2020-2023  润新知