1. 程式人生 > 實用技巧 >插頭dp [入土]

插頭dp [入土]

題目連結

西江月·證明

即得易見平凡,仿照上例顯然。

留作習題答案略,讀者自證不難。

反之亦然同理,推論自然成立。

略去過程QED,由上可知證畢

#include <stdio.h>
#include <memory.h>
#include <math.h>
#include <algorithm>
#include <iostream>
using namespace std;
long long dp[11][2048];
int w, h;

bool TFL(int ovo){
	int i = 0;
	while(i < w){
		if(ovo & (0x1 << i)){
			if(i == w - 1 or (ovo & (0x1 << (i + 1))) == 0) return 0;
			i += 2;
		}else i ++;
	}return 1;
}

bool CT(int sa, int sb){//判斷狀態(i, sa)和(i-1, sb)是否相容.(相容性測試
	int i = 0;
	while(i < w){
		if((sa & (0x1 << i)) == 0){
			if((sb & (0x1 << i)) == 0) return 0;
			i ++;
		}
		else{
			if((sb & (0x1 << i)) == 0) i ++;
			else if((i == w - 1) or !((sa & (0x1 << (i + 1))) and (sb & (0x1 << (i + 1))))) return 0;
			else i += 2;
		}
	}
	return 1;
}

int main(){
	while(1){
		cin >> h >> w;
		if(h == 0 and w == 0) break;
		if(w > h) swap(w, h); //H是大的 W是小的
		int ovo = 2 << (w - 1);
		memset(dp, 0, sizeof(dp));
		for(int j = 0; j < ovo; j++) if(TFL(j)) dp[0][j] = 1;
		for(int i = 1; i < h; i ++)
		  for(int j = 0; j < ovo; j ++) // iterate all status for line i
		    for(int k = 0; k < ovo; k ++) // iterate all status for line i-1
		      if(CT(j, k)) dp[i][j] += dp[i - 1][k];
		printf("%lld\n", dp[h - 1][ovo - 1]);
	}
	return 0;
}

QED