状压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;
}
posted @ 2025-08-17 21:23  KK_SpongeBob  阅读(8)  评论(0)    收藏  举报