P1879 [USACO06NOV]玉米田Corn Fields[轮廓线DP]

状压暴力显然可做。但是数据出的再大一点就要稳T了。理论$O(n4^m)$,只不过实际跑不满。

考虑用轮廓线DP,设$f(i,j,S)$为处理到$(i,j)$时候(这格还不确定)的轮廓线为$S$的情况(相当于把$(i,1\sim j-1)$和$(i-1,j\sim m)$的$m$个数用$S$压起来)下有多少种合法方案,然后考虑$(i,j)$这个格子填什么。

不管怎么样,这格都可以填0,将这个推向$f(i,j+1,S')$。如果左一格或上一格填了1或者这格有障碍,那不能填1,否则可以填1,同理推向$f(i,j+1,S'')$。

这里的$S'和S''$是位运算将第$j$位进行$0/1$变换的。

注意考虑细节:一行的轮廓线推完($j$循环到$m$结束后)的这个状态是要作为下一行的起始状态的。也就是$f(i,m,S)$应当推向$f(i+1,1,S')$。

我们可以通过直接滚动数组来一格一格往下推,避免换行之类的操作,详见code。

其次,这样DP不需要考虑相邻合不合法,因为我在填的时候推向后面的状态这个操作已经是保证他合法的了,即使是枚举出了不合法的,他的方案数也会是$0$,也没办法有累加作用。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #define dbg(x) cerr << #x << " = " << x <<endl
 7 using namespace std;
 8 typedef long long ll;
 9 typedef double db;
10 typedef pair<int,int> pii;
11 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
12 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
13 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
14 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
15 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
16 template<typename T>inline T read(T&x){
17     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
18     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
19 }
20 const int P=1e8;
21 int mp[14][14],f[2][1<<12];
22 int m,n,now,tmp,ans;
23 
24 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
25     read(n),read(m);
26     for(register int i=1;i<=n;++i)for(register int j=1;j<=m;++j)read(mp[i][j]);
27     f[0][0]=1;
28     for(register int i=1;i<=n;++i){
29         for(register int j=1;j<=m;now^=1,++j){
30             for(register int k=0;k<1<<m;++k)if(f[now][k]){
31                 int p2=k&(1<<j-1),p1=j==1?0:k&(1<<j-2);
32                 tmp=p2?k^(1<<j-1):k,f[now^1][tmp]+=f[now][k],f[now^1][tmp]>=P&&(f[now^1][tmp]-=P);
33                 if(mp[i][j]&&!p1&&!p2)
34                     tmp=k|(1<<j-1),f[now^1][tmp]+=f[now][k],f[now^1][tmp]>=P&&(f[now^1][tmp]-=P);
35                 f[now][k]=0;
36             }
37         }
38     }
39     for(register int k=0;k<1<<m;++k)ans+=f[now][k],ans>=P&&(ans-=P);
40     return printf("%d\n",ans),0;
41 }
View Code

理论$O(nm2^m)$。

转载于:https://www.cnblogs.com/saigyouji-yuyuko/p/11532869.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值