在此我向各位博友求助,特别想知道除了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; }