• POJ 3254 Corn Fields


    POJ 3235 Corn Fields


    题意:在一个n*m的草地上面放牛,两头牛不能挨着,并且只能最肥沃的草地上放牛。问有多少中放养方式。


    思路:状压dp主要是运用的的位运算,然后用dp的思想去找转移方程。

    这篇博客讲的很详细,推荐一下

    对于本题而言可以这样考虑,把每一排的所有不相邻的情况看成是一个集合(看成是save[]的话),对于样例可以得到下面的集合
    样例集合

    注:这是对于m==3,所有的情况的集合

    每一次在这个集合中选取符合条件的(条件就是只能在肥沃的土地上面放牛),换句话说就是,用一个集合(状态压缩)维护所有不相邻的情况,在这个的基础上面再去考虑那些土地能放牛那些不能。
    这是每一排的处理。

    对于排与排之间,可以这样想, 第i排的所有情况=第i排本身的所有排列+第i的所有不与第i-1排相邻的所有情况(dp思想)。 用数组dp[i][k]表示第i排在情况k的的条件下的放牛的方式。(情况k指的的原来的已经维护好的数组save[k]的情况下。 一开始在这上面我晕了好长时间,后来看了几遍代码自己感受了一下才算是知道。)

    转移方程可写成 dp[i][k]=(dp[i][k]+dp[i-1][p]),

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    #define inf 0x3f3f3f
    #define MOD 1000000000
    int n,m;
    int cur[20];
    int dp[20][600];
    int save[600];
    int num=0;
    bool rec(int x) //判断是否有相邻
    {
        if(x&(x<<1)) return false; // 
        return true;
    }
    void inint() // 把所有的情况都处理出来,然后放到集合里面去;
    {
        num=0;
        int top=1<<m;
        for(int i=0; i<top; i++){
            if(rec(i)) save[num++]=i;
        }
    }
    bool check(int x,int k) //检查该集合的基础上,有没有符合条件放牛的;
    {
        if(x&cur[k]) return false;
        return true;
    }
    /*   ps:原作者的直接拿过来了
    此处,注意要用相反存储的数据来判断,
    因为若10101001是一种可行状态,则可知101001也可行(是前者的一部分)
    这时x即为10101001,cur[k]为10110,x&cur[k]=0,即符合条件
    */
    int main()
    {
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            memset(dp,0,sizeof(dp));
            memset(cur,0,sizeof(cur));
            memset(save,0,sizeof(save));
            inint();
            for(int i=0; i<n; i++){
                int x;
                cur[i]=0;
                for(int j=0; j<m; j++){
                    scanf("%d",&x);
                    if(x==0) cur[i]+=1<<(m-j-1); //反向表示土地的肥沃和贫瘠
                }
            }
            for(int j=0; j<num; j++){ //先处理完第一排
                if(check(save[j],0)) dp[0][j]=1;
            }
            for(int i=1; i<n; i++){
                for(int j=0; j<num; j++){
                    if(!check(save[j],i)) continue;
                    for(int k=0; k<num; k++){
                        if(!check(save[k],i-1)) continue; //j代表的是当前排,k代表的是i-1排,为了检查相邻两排的非法情况
                        if(save[j]&save[k]) continue;
                        dp[i][j]=(dp[i][j]+dp[i-1][k])%MOD;
                    }
                }
            }
            int ans=0;
            for(int i=0; i<num; i++){
                ans=(ans+dp[n-1][i])%MOD;
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    低情商大神的思维,高情商的你会懂么?为什么非常多计算机老师都是坏脾气?为什么提问没人回答?为什么要通过网络自主学习?
    Add Binary
    Codeforces Round #252 (Div. 2) B. Valera and Fruits(模拟)
    cocos2d-x项目101次相遇: Scenes , Director, Layers, Sprites
    Android应用性能优化系列视图篇——隐藏在资源图片中的内存杀手
    Android屏幕信息获取
    android 比较靠谱的图片压缩
    Android 图片压缩,基于比例和质量压缩
    android Bitmap类方法属性 详细说明
    Android入门——Bitmap和BitmapFactory
  • 原文地址:https://www.cnblogs.com/zzulipomelo/p/5310620.html
Copyright © 2020-2023  润新知