2018.11.06【NOIP2015】【洛谷P2668】斗地主(DP预处理)(搜索)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/83782942

传送门


解析:

其实不考虑点数大小的话只有张数对我们是有用的。所以可以预处理出有 i i 张单牌, j 2 j*2 张对子, k 3 k*3 张三条, z z 个炸弹, l l 个王的情况下打完散牌要的最少次数,顺子通过贪心搜索一下就行了。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline int getint(){
	re int num;
	re char c;
	while(!isdigit(c=gc()));num=c^48;
	while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
	return num;
}

inline void ckmin(int &x,cs int &val){
	if(x>val)x=val;
}

int f[26][14][12][8][3];
inline void init(){
	memset(f,0x3f,sizeof f);
	f[0][0][0][0][0]=0;
	for(int re z=0;z<7;++z)
	for(int re k=0;k<10;++k)
	for(int re i=0;i<24;++i)
	for(int re j=0;j<13;++j)
	for(int re l=0;l<3;++l){
		int &x=f[i][j][k][z][l];
		if(i>0)ckmin(x,f[i-1][j][k][z][l]+1);
		if(j>0)ckmin(x,f[i][j-1][k][z][l]+1);
		if(k>0)ckmin(x,f[i][j][k-1][z][l]+1);
		if(z>0)ckmin(x,f[i][j][k][z-1][l]+1);
		if(l>0)ckmin(x,f[i][j][k][z][l-1]+1);
		if(l>1)ckmin(x,f[i][j][k][z][l-2]+1);
		
		if(k>0&&i>0)ckmin(x,f[i-1][j][k-1][z][l]+1);
		if(k>0&&l>0)ckmin(x,f[i][j][k-1][z][l-1]+1);
		if(k>0&&j>0)ckmin(x,f[i][j-1][k-1][z][l]+1);
		
		if(z>0&&i>1)ckmin(x,f[i-2][j][k][z-1][l]+1);
		if(z>0&&i>0&&l>0)ckmin(x,f[i-1][j][k][z-1][l-1]+1);
		if(z>0&&l>1)ckmin(x,f[i][j][k][z-1][l-2]+1);
		if(z>0&&j>0)ckmin(x,f[i][j-1][k][z-1][l]+1);
		if(z>0&&j>1)ckmin(x,f[i][j-2][k][z-1][l]+1);
		if(z>1)ckmin(x,f[i][j][k][z-2][l]+1);
		
		if(z>0)ckmin(x,f[i+1][j][k+1][z-1][l]);
		if(z>0)ckmin(x,f[i][j+2][k][z-1][l]);
		if(k>0)ckmin(x,f[i+1][j+1][k-1][z][l]);
	}
}

int ans;
int a[20];
int cnt[6];int T,n;
void dfs(int x){
	if(x>=ans)return ;
	memset(cnt,0,sizeof cnt);
	for(int re i=1;i<=13;++i)++cnt[a[i]];cnt[5]=a[14];
	ans=min(ans,x+f[cnt[1]][cnt[2]][cnt[3]][cnt[4]][cnt[5]]);
	for(int re k=1;k<=3;++k){
		for(int re i=1;i<=12;++i){
			bool flag=true;
			int cnt=(k==1)?5:(k==2?3:2);
			while(flag&&i+cnt-1<=12){
				for(int re j=1;j<=cnt;++j)if(a[i+j-1]<k){
					flag=false;
					break;
				}
				if(!flag)break;
				for(int re j=1;j<=cnt;++j)a[i+j-1]-=k;
				dfs(x+1);
				for(int re j=1;j<=cnt;++j)a[i+j-1]+=k;
				++cnt;
			}
		}
	}
}

signed main(){
	init();
	T=getint();
	n=getint();
	while(T--){
		ans=n;
		memset(a,0,sizeof a);
		for(int re i=1;i<=n;++i){
			int num=getint();getint();
			if(num==0){
				++a[14];
				continue;
			}
			if(num>2)++a[num-2];
			else ++a[num+11];
		}
		dfs(0);
		printf("%d\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/83782942
今日推荐