• HihoCoder第九周 状态压缩 二 与POJ2411总结


    在此我向各位博友求助,特别想知道除了HihoCoder上面的结果要对1e9+7取余之外,这两道题还有什么其他的问题,都是骨牌覆盖问题,都是状态压缩+dp,为什么我能过poj2411的程序过不了HihoCoder,还不是其他诸如TimeLimited,而是Wrong Answer,这个问题我想了很久,还是不知道是怎么回事,如果有神通广大的博友知道答案,希望你能告诉我。顺便说一下,HihoCoder给的那个hint只看懂了一部分递推的公式,其中满足的那个条件还是不懂。

    两个题目的连接地址:

    http://hihocoder.com/problemset/problem/1048

    http://poj.org/problem?id=2411

    骨牌覆盖问题我想了很久很久,我自己也知道对于每一个位置上的骨牌来说,有三种可能,有可能是上楼的骨牌,有可能是下楼的骨牌,也有可能是同楼层的骨牌。但当时我思考的时候,就在想,比方说2*2这个位置。


    有两种摆法,我当时就在想如何记录result[1][1]=2,因为这两种条件都满足了,所以result[1][1]=2?那之后的result[1][2]呢?

    觉得这样不对。就完全没有思路了。

    最后看了一个动态规划算法,但其实这道题算动态规划的话,我更觉得像枚举,枚举上楼的所有情况,枚举下楼的所有情况,看这两种情况里面,哪些合拍,之后才是动态规划记录其和的事。

    首先觉得这种记录方法很棒,即记录两层楼的状态,如果是01代表竖着一个骨牌。如果是10代表,楼上的骨牌怎么来的不知道,但从楼下竖着一块牌是确定的。如果是11,说明都是横着的牌,所以楼上和楼下的下一张牌都要是1才能满足条件。如果是00,则GG。

    之后就是第一层的初始化,只需记住1要成对出现就行了(因为这是第一层)。

    被这题折磨太久,印象实在太深。希望交流。

    #include <iostream>
    #include <cstring>
    using namespace std;
    
    #define M 12
    
    long long dp[12][1<<M];
    int n,m;
    
    int init_ok(int i)
    {
    	int count;
    	for(count=m-1;count>=0;)
    	{
    		if((i>>count)&1)
    		{
    			if((i>>(count-1))&1)
    			{
    				count= count-2;
    				continue;
    			}
    			else
    			{
    				count--;
    				return 0;
    			}
    		}
    		else
    		{
    			if(count==1&&(i&1))
    				return 0;
    			else
    			{
    				count--;
    				continue;
    			}
    		}
    
    	}
    	return 1;
    }
    
    void init()
    {
    	int count;
    	int kongjian = (1<<m)-1;
    
    	memset(dp,0,sizeof(dp));
    
    	for(count=0;count<=kongjian;count++)
    	{
    		if(init_ok(count))
    			dp[0][count]=1;
    	}
    }
    
    bool match(int a, int b)
    {
    	for (int i = 1; i < 1 << m;)
    	{
    		if (((a & i) == 0) && ((b & i) == 0))
    			return false;
    		if ((a & i) && (b & i))
    		{
    			if ((a & (i << 1)) && ((b & (i << 1))))
    			{
    				i <<= 2;
    				continue;
    			}
    			else
    				return false;
    		}
    		i <<= 1;
    	}
    	return true;
    }
    
    int main()
    {
    
    	while(scanf_s("%d %d",&n,&m),n &&m)
    	{
    		int i,shang,xia;
    		if(n < m)
    			i = n ,n = m,m =i;
    		int kongjian = (1<<m)-1;
    
    		init();
    
    		for(i=1;i<n;i++)
    		{
    			for(xia = 0;xia<=kongjian;xia++)
    			{
    				for(shang=0;shang<=kongjian;shang++)
    				{
    					if(match(shang,xia))
    						dp[i][xia]+=dp[i-1][shang];
    
    				}
    			}
    		}
    
    		cout<<dp[n-1][kongjian]<<endl;
    	}
    
    	return 0;
    }
    


    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    最近积累的JS 东西,分享一下
    C#定时任务框架Quartz.NET
    如何成为微软社区MVP以及年终总结
    git 基于某个分支创建分支
    iframe跨域-Js通信的一种方式
    tcp连接建立断开过程及状态变化
    MySQL-InnoDB的事务隔离与锁
    MySQL索引原理总结
    php gd实现简单图片验证码与图片背景文字水印
    php 取post数据的三种方式
  • 原文地址:https://www.cnblogs.com/lightspeedsmallson/p/4785901.html
Copyright © 2020-2023  润新知