hdu 4804 轮廓线dp

脑子不好使,dp理解起来有难度,特别是没讲解的时候。看了半天终于看懂别人的代码了。

#include<stdio.h>
#include<string.h>
const int N=102,M=11,mod=1e9+7;
int bt[M],cur;
int n,m,c,d;
char mp[N][M];
int dp[2][1<<10][22];//第i个格子,前i个状态为j,有k个1*1的方案数

void update(int ns,int s,int nk,int k){//状态转移[s][k]->[ns][nk]
	if(ns&bt[m])//如果第m+1位不是1,那么说明有空格没填充,不符合条件
		dp[1-cur][ns^bt[m]][nk]=(dp[1-cur][ns^bt[m]][nk]+dp[cur][s][k])%mod;
}

int main(){
	bt[0]=1;
	for(int i=1;i<M;i++)
		bt[i]=bt[i-1]*2;
	while(~scanf("%d %d %d %d",&n,&m,&c,&d)){
		for(int i=0;i<n;i++)
			scanf("%s",mp[i]);
		memset(dp,0,sizeof dp);
		cur=0;
		int state=bt[m]-1;
		dp[0][state][0]=1;

		for(int i=0;i<n;i++){
			for(int j=0;j<m;j++){
				if(mp[i][j]=='0'){//不能放
					for(int k=0;k<=d;k++)
						for(int s=0;s<=state;s++)
							if(dp[cur][s][k])
								update((s<<1)^1,s,k,k);
				}
				else{//能放
					for(int k=0;k<=d;k++)
						for(int s=0;s<=state;s++)
							if(dp[cur][s][k]){
								update((s<<1),s,k,k);//不放
								update((s<<1)^1,s,k+1,k);//放1*1
								if(j&&(s&1)==0)//如果是第1列或左边不能放--不更新
									update((s<<1)^3,s,k,k);//横放1*2
								if(i&&(s&bt[m-1])==0)//如果是第1行或上边不能放--不更新
									update((s<<1)^bt[m]^1,s,k,k);//竖放1*2
							}
				}
				memset(dp[cur],0,sizeof dp[cur]);
				cur=1-cur;
			}
		}
		int ans=0;
		for(int i=c;i<=d;i++)
			ans=(ans+dp[cur][state][i])%mod;
		printf("%d\n",ans);
	}
	return 0;
}
/*
s表示当前位置的前m位的状态,s<<1表示向下一个滚动一位,^1是放1*1,^3是横放1*2,^bt[m]^1是竖放2*1
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值