poj 2411 新写法

别以为我在刷水题。。。。

今天做了场srm,500pt想到了是dp但是无从下手,但是看了rng_58的神代码后顿觉海阔天空啊(盯着看了一个下午),相比于一年前的写法,真的是不忍直视啊,

TC真是个好地方。。。赞!

其实就是将普通的铺砖块问题用类似于插头dp逐格递推的思路来写。下面的代码相信大家应该都能看懂。

#include <cstdio>
#include <cstring>
#include <algorithm>
long long dp[2][1<<11];
int main() {
    int n , m;
    while(scanf("%d%d",&n,&m),n||m) {
      int cur = 0 , nxt = 1;
      dp[cur][0] =  1;
       for(int i = 0; i < n; i++) {
          for(int j = 0; j < m; j++) {
            memset(dp[nxt],0,sizeof(dp[nxt]));
            for(int s = 0; s < (1<<m); s++) if(dp[cur][s]){
                if(s&1){dp[nxt][s>>1] += dp[cur][s];continue;}
                if(j+1<m && !(s&2) ){
                    int mask = ( s | 2 ) >> 1;
                    dp[nxt][mask] += dp[cur][s];
                }
                if(i+1<n) {
                    int mask = (s | (1<<m)) >> 1;
                    dp[nxt][mask] += dp[cur][s];
                }
            }
            std::swap(cur,nxt);
          }
       }
       printf("%I64d\n",dp[cur][0]);
    }
    return 0;
}

下面是一年前的写法。。。

#include<stdio.h>
#include<string.h>
int h,w;
__int64 dp[15][2050];
void dfs1(int row,int state,int col,int state2){
	if(col>w) return ;
	if(col==w) {
		dp[row+1][state2]+=dp[row][state];
		return ;
	}
	if(!(state&(1<<col))) dfs1(row,state,col+1,state2+(1<<col));
	else dfs1(row,state,col+1,state2);
}
void dfs2(int row,int state,int col,int state2){
	if(col>w) return ;
	if(col==w) {
		if(state2!=state)  
		   dp[row][state2]+=dp[row][state];
		return ;
	}
	if(!(state&(1<<col)) &&	!(state&(1<<(col+1))))
		dfs2(row,state,col+2,state2+(1<<col) + (1<<(col+1)));
	dfs2(row,state,col+1,state2);
}
void gao(){
	int i,j;
	dp[0][(1<<w)-1]=1;
	for(i=0;i<h;i++){
          for(j=0;j<(1<<w);j++)
			  if(dp[i][j])
				  dfs1(i,j,0,0);
		  for(j=(1<<w)-1;j>=0;j--)
		      if(dp[i+1][j])
				  dfs2(i+1,j,0,j);
	}
}
int main(){
	while(scanf("%d%d",&h,&w)!=EOF && h+w){
		int temp;
		if(h<w){
			temp=h;h=w;w=temp;
		}
		memset(dp,0,sizeof(dp));
		gao();
		printf("%I64d\n",dp[h][(1<<w)-1]);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值