[Usaco2006 Nov]Corn Fields(状压dp水题)

啥?你说这是水题?

你还别说它就是个水题

那我为啥还要做?

因为我正要开始学呢呀

好的开始

题意:给你个矩阵,有的地方可以放牛有的不能,任意两头牛不能挨着,有多少种放法(一头不放当然也算)

好的所谓状压

就是将各种可以以1,0表示的图压成一个二进制数

比如

1 0 1 1 0 1 0

你就可以压成186

然后我们就可以愉快地开始了

第一步

因为不允许挨着,所以搜出一行上所有可能的放置方法

void dfs(int s,int pla)//搜到了第几位,当前状态 
{
    if(pla>n)//搜完一整行的一种状态,保存 
    {
        scount++;
        sta[scount]=s;
        return;
    }
    dfs(s,pla+1);//pla位置上不放 
    dfs(s+(1<<(pla-1)),pla+2);//
}

搜出所有可能放法之后

你就可以开始dp了

按照它的要求走就行

 1     for(int i=1;i<=m;i++)for(int j=1;j<=n;j++)
 2     {
 3         scanf("%d",&stain);
 4         allow[i]|=((stain^1)<<(j-1));//不能放的标记成1(自行思考一下为什么不是标成0) 
 5     }
 6     dfs(0,1);
 7     dp[0][0]=1;
 8     for(int i=1;i<=m;i++)//每一行 
 9     {
10         for(int s=1;s<=scount;s++)//枚举每一个可能状态 
11         {
12             if(sta[s]&allow[i])//如果在这一行不允许这么放 
13             {
14                 dp[i][sta[s]]=0;
15                 continue;
16             }
17             for(int ss=1;ss<=scount;ss++)//枚举上一行所有可能状态 
18             {
19                 if(sta[s]&sta[ss])continue;//如果有挨着的那就不行 
20                 dp[i][sta[s]]+=dp[i-1][sta[ss]];
21                 dp[i][sta[s]]%=mo;
22             }
23         }
24     }

好的我就不放AC代码了...(被打死)

 1 #include<cstdio>
 2 #define ful 1<<12
 3 #define mo 100000000
 4 void swap(int &a,int &b)
 5 {
 6     int kkk=a;
 7     a=b;
 8     b=kkk;
 9 }
10 int dp[13][ful],n,m,sta[ful],allow[13];
11 int scount;
12 void dfs(int s,int pla)
13 {
14     if(pla>n)
15     {
16         scount++;
17         sta[scount]=s;
18         return;
19     }
20     dfs(s,pla+1);
21     dfs(s+(1<<(pla-1)),pla+2);
22 }
23 int main()
24 {
25     scanf("%d%d",&m,&n);
26     int stain;
27     for(int i=1;i<=m;i++)for(int j=1;j<=n;j++)
28     {
29         scanf("%d",&stain);
30         allow[i]|=((stain^1)<<(j-1));
32     }
33     dfs(0,1);
37     dp[0][0]=1;
38     for(int i=1;i<=m;i++)
39     {
40         for(int s=1;s<=scount;s++)
41         {
42             if(sta[s]&allow[i])
43             {
44                 dp[i][sta[s]]=0;
46                 continue;
47             }
48             for(int ss=1;ss<=scount;ss++)
49             {
50                 if(sta[s]&sta[ss])continue;
51                 dp[i][sta[s]]+=dp[i-1][sta[ss]];
52                 dp[i][sta[s]]%=mo;
53             }
54         }
55     }
58     int ans=0;
59     for(int s=1;s<=scount;s++)
60     {
61         ans+=dp[m][sta[s]];
62         ans%=mo;
63     }
64     printf("%d",ans);
65     return 0;
66 }

猜你喜欢

转载自www.cnblogs.com/rikurika/p/cornfield.html