BZOJ 1860: [Zjoi2006]Mahjong麻将

题目: http://www.lydsy.com/JudgeOnline/problem.php?id=1860

/*
* BZOJ 1860: [Zjoi2006]Mahjong麻将
*
* 分析:
* 据说有DP解,暂时没想出来。。。直接暴力dfs+hash
* dfs(pos,two,state):pos表示当前的位置,two表示是否有对,state表示状态
* 暴力枚举四种情况,然后每次进行搜索前进行hash判重。
* hash判重时使用像池子法一样的方式解决冲突问题。
*
* */

#include <cstdio>
#include <iostream>
#include <cstring>

using namespace std;

const int maxm = 2e5+10;
const int mod = 99997;
const int maxn = 105;
const int n = 100;
const int seed = 103;

typedef unsigned long long ll;

ll p[maxn];
int a[maxn];

int po[mod+3],tol;

struct Hash{
	ll val;
	int next;
}edge[maxm];

void ins(ll x){ //insert x
	int y = int(x%mod);
	edge[++tol].val = x;
	edge[tol].next = po[y];
	po[y] = tol;
}

bool has(ll x){ //has x ?
	int y = int(x%mod);
	for(int i=po[y];i;i=edge[i].next)
		if(edge[i].val==x)
			return true;
	return false;
}

bool dfs(int pos,bool two,ll state){
	if(has(state))
		return false;
	ins(state);
	
	while(pos<=n&&a[pos]==0)
		pos ++;
	if(pos>n)
		return two;
	
	if(pos+2<=n&&a[pos+1]&&a[pos+2]){ //three continous
		a[pos]   --;
		a[pos+1] --;
		a[pos+2] --;
		if(dfs(pos,two,state-p[pos]-p[pos+1]-p[pos+2]))
			return true;
		a[pos]	 ++;
		a[pos+1] ++;
		a[pos+2] ++;
	}

	if(a[pos]>=3){ //three
		a[pos] -= 3;
		if(dfs(pos,two,state-p[pos]*3))
			return true;
		a[pos] += 3;
	}
1
	if(a[pos]>=4){ // four
		a[pos] -= 4;
		if(dfs(pos,two,state-p[pos]*4))
			return true;
		a[pos] += 4;
	}

	if(a[pos]>=2 && !two){ // pair
		a[pos] -= 2;
		//对于一对的特殊判断,比如可能存在5 = 3 + 2 = 4 +1(连续型但之前搜过不行)
		if(dfs(pos,true,state-p[pos]*2-p[n+1]))
			return true;
		a[pos] += 2;
	}

	return false;
}

int main(){
	int ncase,x;
	cin>>ncase;
	
	p[1] = 1;
	for(int i=2;i<=n+1;i++)
		p[i] = p[i-1]*seed;

	while(ncase--){
		ll state = 0;
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
			state *= seed;
			state += a[i];
		}
		state *= seed; //对于一对的特殊判断
		state ++;
		memset(po,0,sizeof(po));
		tol = 0;
		dfs(1,false,state)?puts("Yes"):puts("No");
	}
	return 0;
}

  

posted @ 2012-12-30 08:07  yejinru  阅读(366)  评论(0编辑  收藏  举报