状压DP总结---二维问题
只写了两道题QAQ
T1 Luogu P1879
通读后发现只有以下两个限制条件:
-
肥沃的土地才能种草
-
相邻(左右,上下)的土地不能同时种草
先处理第一种情况,我们用f[i]表示第i行的土壤肥沃状态,sta1表示第i行的当前状态
那么,只要将f[i]全部翻转(10互换)再按位与上sta1,判断是否不为0即可
| 非法(不肥沃却种了) | ||||
|---|---|---|---|---|
| 翻转的f[i] | 1 | 1 | 0 | 0 |
| sta1 | 1 | 0 | 1 | 0 |
| & | 1 | 0 | 0 | 0 |
第二种情况分两种考虑:
横向:可以位移1位后与原先的按位与一下:
| 非法(相邻的种了) | ||||
|---|---|---|---|---|
| 原来的 | 1 | 1 | 0 | 0 |
| 位移后的 | 1 | 0 | 0 | 0 |
| & | 1 | 0 | 0 | 0 |
纵向的还需要知道上一行的情况,用sta2表示
直接位与判断即可
DP四步法:
-
状态:dp[sta][i]表示枚举了前i行,第i行状态为sta的方案数
-
答案:sum(dp[所有sta][n])
-
方程:dp[sta1][i]+=dp[sta2][i-1]
-
初始值&边界:dp[i][j]=0,dp[0][0]=1;
代码:
#include<bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
const int maxn=1e3+5,mod=1e8,inf=1e18;
int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0' && ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
void write(int x){if(x<0){putchar('-'),x=-x;}if(x>9){write(x/10);}putchar(x%10+'0');return;}
int fpow(int a,int b,int p){if(b==0){return 1;}int res=fpow(a,b/2,p)%p;if(b%2==1){return((res*res)%p*a)%p;}else{return(res*res)%p;}}
int dp[(1<<12)][15];
int vis[maxn];
int n,m;
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=0;j<m;j++){
int x;
cin>>x;
x^=1;
vis[i]|=(x<<j);
}
}
dp[0][0]=1;
for(int i=1;i<=n;i++){
for(int status=0;status<(1<<m);status++){
if(status&(status<<1)){
continue;
}
if(status&vis[i]){
continue;
}
for(int status1=0;status1<(1<<m);status1++){
if(status&status1){
continue;
}
dp[status][i]+=dp[status1][i-1];
dp[status][i]%=mod;
}
}
}
int sum=0;
for(int status=0;status<(1<<m);status++){
sum+=dp[status][n];
sum%=mod;
}
cout<<sum;
return 0;
}
本人(KK_SpongeBob)蒟蒻,写不出好文章,但转载请注明原文链接:https://www.cnblogs.com/OIer-QAQ/p/19043735

浙公网安备 33010602011771号