• [poj 2978]Colored Stones[状态压缩DP]


    题意:

    给出n个石子,一共m种颜色.问最少去掉几个石子使得同种颜色全连续.

    思路见注释.

    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    
    const int kMAX=105;
    
    /// dp[x][y][z],x指的是[到达第x个石子,包含(意思是参与讨论,并不是说一定留下)第x个石子]的情况下,颜色组合为y(每种颜色占一位),
    /// 最后一颗石子的颜色为z的最多剩余石子数,因为[第x颗石子去留不一定],所以z不一定等于x的颜色
    int dp[kMAX][1<<6][6];
    
    int main()
    {
        int n,m,tmp;
    
        while(scanf("%d%d",&n,&m)==2 && (n+m))
        {
            memset(dp,0,sizeof(dp));
            int len=(1<<m);//状态的总数
            for(int i=1;i<=n;++i)//一颗一颗拿石子
            {///拿起一颗石子,要进行两重循环:遍历所有的颜色组合->遍历所有的结尾种类
             ///i是递增的,而后两维则根据选择的情况来确定
                scanf("%d",&tmp);
                --tmp;//编号修正,可直接对应位置
                for(int j=0;j<len;++j)
                {
                    for(int k=0;k<m;++k)///对于每种颜色k结尾的情况
                    {
                        if(!(j&(1<<tmp))) /// 如果第i颗石子的颜色[不存在于当前研究的状态j中]
                        {
                            dp[i][ j|(1<<tmp) ][tmp] = max(dp[i][ j|(1<<tmp) ][tmp], dp[i-1][j][k]+1);///使用这颗石子
                            ///使用这颗石子时,所对应的dp下标随之转移.x坐标跳转到更靠下的位置(也就是第二维)
                            ///当只改变k时,上式左边对应的位置是不变的.对于不同的k,选择出一种方案使得左值最大(max使得其达到最大时可以保持住)
    
                            /**昨天的数位dp预处理(HDU3555Bomb)都是确定的转移关系,而对于"选择最佳方案"类的dp问题,一般是取最值的(如背包)**/
    
                            ///两重循环,只是保证了每种情况都会check一遍,并不是说在当前循环中就一定填哪个位置.
                            ///从这个层面上说,体现了Dynamic.这也解释了为什么需要取max:因为这个位置可能之前已经填过了,
                            ///也就是通过之前的某种路线已经到达过这个状态,取max就是动态的选取最优的路线.数值已经刻画了选择的历史.
    
                            dp[i][j][k] = max(dp[i][j][k], dp[i-1][j][k]);///不用这颗石子
                            /// 不用这颗石子时,因为一样是讨论到了i,所以同样要更新
    
                            ///总的来说,每次更新都不能直接覆盖原来的值,而要去max,以免覆盖了之前已经达到的可行的方案.而且总不会出错.
                        }
                        else    /// 如果第i颗石子的颜色[存在于当前研究的状态j中]
                        {
                                if(k == tmp)
                                    dp[i][j][k] = max(dp[i][j][k], dp[i-1][j][k]+1);
                                    /// 如果第i颗石子的颜色和在i前面剩余石子中的最后一颗石子颜色一样,则i必定留下来
                                else
                                    dp[i][j][k] = max(dp[i][j][k], dp[i-1][j][k]); /// 否则就不留
                        }
                    }
                }
            }
            int ans=0;
            for(int k=0;k<m;++k)
                for(int j=0;j<len;++j)
                    ans=max(ans,dp[n][j][k]);
            printf("%d
    ",n-ans);
        }
    
        return 0;
    }
    


    自己敲一遍~

    #include <cstdio>
    #include <cstring>
    using namespace std;
    int max(int a, int b)
    {
        int diff = b - a;
        return b - (diff & (diff >> 31));
    }
    const int MAXN = 105;
    int dp[MAXN][1<<6][6];
    /** 324K 0MS
            dp[i][j][k]:
                dealing with the i-th stone
                with status j
                end up with color k;
    **/
    int main()
    {
        int n,m;
        while(scanf("%d %d",&n,&m)==2 && (n+m))
        {
            memset(dp,0,sizeof(dp));
            int tmp;
            int len = 1<<m;
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&tmp);
                tmp--;
                for(int j=0;j<len;j++)
                {
                    for(int k=0;k<m;k++)
                    {
                        if(!(j & (1<<tmp)))
                        {
                            dp[i][j|(1<<tmp)][tmp] = max(dp[i][j|(1<<tmp)][tmp],dp[i-1][j][k]+1);
                            dp[i][j][k] = max(dp[i][j][k],dp[i-1][j][k]);
                        }
                        else
                        {
                            if(k==tmp)
                                dp[i][j][tmp] = max(dp[i][j][tmp],dp[i-1][j][tmp]+1);
                            else
                                dp[i][j][k] = max(dp[i][j][k],dp[i-1][j][k]);
                        }
                    }
                }
            }
            int ans = 0;
            for(int j=0;j<len;j++)
                for(int k=0;k<len;k++)
                    ans = max(ans,dp[n][j][k]);
            printf("%d
    ",n - ans);
        }
    }
    


  • 相关阅读:
    在Window上Vim包的选择
    如何在apache官网下载将将jar包
    hdu1870
    hdu1710(Binary Tree Traversals)
    poj 3252 Round Numbers 【推导·排列组合】
    3905
    Find them, Catch them
    Argus
    Team Queue
    Terrible Sets
  • 原文地址:https://www.cnblogs.com/riskyer/p/3249396.html
Copyright © 2020-2023  润新知