• poj2411 Mondriaan's Dream 棋盘覆盖


    问题描述:

    给出一个n*m的棋盘,及一个小的矩形1*2,问用这个小的矩形将这个大的棋盘覆盖有多少种方法。

    由于我们放置小矩形的时候可以横着放也可以竖着放,那么就会产生不同的方法,但是必须满足不产生空的未覆盖的空格子。

    首先我们用二进制1 0表示在某一个问题放置或者不放置,那么有m列的棋盘,每一行有2*m个状态了,我们现在就找出每行之间的规律。

    对于一个矩形有3种方法:横放,竖放,不放。由于第i行只跟第i-1行的放置有关系,因为我们必须保证第i-1行使放满的,现在用dp[i][state]表示第i行

    状态为state的方法,那么dp[i][curstate]=sum{dp[i-1][prestate]}.

    1 横放

    如果第i行第d列我们选择横放,那么第i行的第d列及d+1列都是1了,第i-1行第d列及d+1列也都必须为1(保证是满的),及状态转移为:

    d=d+2,curstate=curstate<<2|3,prestate=prestate<<2|3.

    2竖放

    第i行第d列我们选择竖放,那么第i行第d列为1,第i-1行d列必须是0,(因为我们是竖着放的,如果前一行不是空的如何能放下呢),状态转移:

    d=d+1,curstate=curstate<<1|1,prestate=prestate<<1.

    3不妨

    第i行第d列不妨,那么第i-1行d列肯定是1,(保证是满的),状态转移:

    d=d+1,curstate=curstate<<1,prestate=prestate<<1|1.

    这个题目采用记忆化搜索,对已经计算出的状态值方法记录,还有就是初始化的时候将dp[0][2<<m-1]=1,这样第0行使放满的,就不用单独进行初始化了(单独初始化的时候,由于是第一行,不存在竖着放的可能)。

    我们的目标就是求dp[n][2<<m-1]了, 源码如下:

    #include <iostream>
    #include <stdio.h>
    using namespace std;
    const int N=12;
    __int64 dp[N][1<<(N-1)];
    //int dp[N][1<<(N-1)];
    int row,col;
    void init(int r,int c,int s)
    {
    	if(c == col)
    	{
    		dp[r][s]++;
    		return;
    	}
    	if(c+1 <= col)
    		init(r,c+1,s<<1);
    	if(c+2 <=col)
    		init(r,c+2,s<<2|3);
    }
    void dfs(int r,int c,int prestate,int nstate)
    {
    	if(c == col)
    	{
    		dp[r][nstate]+=dp[r-1][prestate];
    		cout<<dp[r][nstate]<<" "<<r<<" "<<nstate<<" "<<prestate<<endl;
    		return;
    	}
    	if(c+1 <= col)
    	{
    		dfs(r,c+1,prestate<<1,nstate<<1|1);
    		dfs(r,c+1,prestate<<1|1,nstate<<1);
    	}
    	if(c+2 <= col)
    		dfs(r,c+2,prestate<<2|3,nstate<<2|3);
    }
    int main()
    {
    	int i;
    	while(scanf("%d%d",&col,&row))
    	{
    		if(!col)
    			break;
    		if(1 == (col * row) %2)
    		{
    			printf("0\n");
    			continue;
    		}
    		if(col > row) //行列变化,让列是小的值,因为行是线性的,而列的可能值是指数的
    		{
    			col^=row;
    			row^=col;
    			col^=row;
    		}
    		memset(dp,0,sizeof(dp));
    		dp[0][(1<<col)-1]=1;
    		//	init(1,0,0);
    		for(i=1;i<=row;i++)
    		{
    			dfs(i,0,0,0);
    		}
    		printf("%I64d\n",dp[row][(1<<col)-1]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Ubuntu开机等待5分钟的取消方法
    329. 矩阵中的最长递增路径
    关于c语言中NULL的数值是否可以被修改
    #pragam在c++(visual studio 2019)编译器中的使用
    当cpu占有率过高时-sleep(0)的妙用
    inline解析
    一、【pytest实战--Web测试】搭建环境
    用openssl aes256 api实现文件加解密-带例程,兼容openssl enc -aes-256-cbc命令
    kali openvas安装
    C++关于变量初始化的琐记
  • 原文地址:https://www.cnblogs.com/buptLizer/p/2214233.html
Copyright © 2020-2023  润新知