Luogu-P1879 [USACO06NOV]玉米田Corn Fields

 

题目

题目链接

 

测试得分:  100

 

 

主要算法 :  状压DP(二进制优化)

 

 

题干:

   状压DP板子

 

分析

  1.就是像之前的互不侵犯一样,只是合法状态还要判断要与玉米地的贫瘠程度,是否可以种植玉米有关

  2.向互不侵犯一样,判读是否两两相邻

  3.好了上代码了

  代码

#include<stdio.h>
#include<stdlib.h>
#define FORa(i,s,e) for(int i=s;i<=e;i++)
#define FORs(i,s,e) for(int i=s;i>=e;i--)
#define gc pa==pb&&(pb=(pa=buf)+fread(buf,1,100000,stdin),stdin)?EOF:*pa++
#define File(name) freopen(name".in","r",stdin);freopen(name".out","w",stdout);

using namespace std;
char buf[100000],*pa,*pb;
inline int read();

const int SUM=4096,N=12,MOD=100000000;
int n,m,ans,f[N+1][SUM+1];
/*f[i][j]代表的是前i行且第i行的状态为j满足的方案数 
j原本是一维的有n个元素的数组,代表的是第i行的状态,但是对于状态只有01两种选择,放与不放
所以可以将01串看作二进制数,则每一个状态对应一个唯一的十进制数,这就是这一题的核心思想状压 
还有就是要符合这片土地是否可以种植 
*/
struct Node{
    int num,s[SUM+1];
}a[N+1];
void Pretreatment(int i,int t)
{
    for(int j=0,jn=(1<<m);j<jn;j++)//枚举每一行的状态 
    {
        if((j&(j<<1))||(j&(j>>1))||(j&t)) continue;
        /*如果有左右两个相邻都种植corn的话就不合法
        还有就是要符合这片土地是否可以种植 
        原本是为0的不能种植,但因为位运算的一些操作是对于1敏感
        所以此处有一种特殊的解决方法,就是将土地初始状态反向转化,0变成1,1变成0
        所以与现在枚举的状态如果有交集,直接忽略*/ 
        a[i].s[++a[i].num]=j;//累加每一行的状态 
    }
}
void Dp()
{
    FORa(i,1,a[1].num) f[1][i]=1;
    FORa(i,2,n)
        FORa(j,1,a[i].num)//枚举这一行所有合法状态
            FORa(k,1,a[i-1].num)//枚举下一行所有合法状态
            {
                if(a[i].s[j]&a[i-1].s[k]) continue;//上下两行不能有同一列号都种植玉米的情况 
                f[i][j]+=f[i-1][k];//合法则累加
            }
    FORa(i,1,a[n].num) ans=(ans+f[n][i])%MOD;//累加答案 
    printf("%d",ans);
}
int main()
{
    scanf("%d%d",&n,&m);
    FORa(i,1,n)
    {
        int t=0,x;
        FORa(j,1,m) scanf("%d",&x),t=(t<<1)+1-x;
        /*要符合这片土地是否可以种植 
        原本是为0的不能种植,但因为位运算的一些操作是对于1敏感
        所以此处有一种特殊的解决方法,就是将土地初始状态反向转化,0变成1,1变成0
        所以与现在枚举的状态如果有交集,直接忽略*/ 
        Pretreatment(i,t); 
    }
    Dp();
    return 0;
}
inline int read()
{
    register char c(gc);register int f(1),x(0);
    while(c<'0'||c>'9') f=c=='-'?-1:1,c=gc;
    while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=gc;
    return x*f;
}
/*2 3
1 1 1
0 1 0*/

 

 

总结:

  1.DP状态的确定

  2.预处理筛选不合法状态

 

posted @ 2019-08-15 12:25  SeanOcean  阅读(210)  评论(0编辑  收藏  举报