2018.11.01 bzoj4325: NOIP2015 斗地主(贪心+搜索)

版权声明:随意转载哦......但还是请注明出处吧: https://blog.csdn.net/dreaming__ldx/article/details/83627443

传送门
原来一直以为是一道大模拟。
没想到是一道搜索+最优性剪枝
如何搜最优呢?
我们考虑怎么最快出完。
大概是应该尽量出当前能出出去最多的吧。
于是我们选择优先出顺子。
这样做有什么好处呢?
我们会发现除了顺子以外的牌都能够直接算最少需要出几轮。
因此把顺子出完之后更新答案就行了。
于是出牌优先级:顺子>四带二>四带一>三带二>三带一>对子>单牌
代码:

#include<bits/stdc++.h>
using namespace std;
int card[4]={0,5,3,2},r,n,a[15],ans,tot[5];
inline int calc(){
	int ret=0;
	memset(tot,0,sizeof(tot));
	for(int i=0;i<=14;++i)if(i^1)++tot[a[i]];
	while(tot[4]&&tot[2]>=2)++ret,--tot[4],tot[2]-=2;
	while(tot[4]&&tot[1]>=2)++ret,--tot[4],tot[1]-=2;
	while(tot[3]&&tot[2])++ret,--tot[3],--tot[2];
	while(tot[3]&&tot[1])++ret,--tot[3],--tot[1];
	return ret+tot[1]+tot[2]+tot[3]+tot[4];
}
inline void dfs(int dep){
	if(dep>=ans)return;
	for(int same=3,j,len;same;--same){
		for(int i=3;i<=13;++i){
			j=i;
			while(a[j]>=same&&j<=14)++j;
			--j;
			if((len=j-i+1)<card[same])continue;
			for(int k=i;k<=i+card[same]-2;++k)a[k]-=same;
			for(int k=i+card[same]-1;k<=j;++k)a[k]-=same,dfs(dep+1);
			for(int k=i;k<=j;++k)a[k]+=same;
		}
	}
	ans=min(ans,dep+calc());
}
int main(){
	scanf("%d%d",&r,&n),ans=n;
	for(int i=1,x,y;i<=r;++i,memset(a,0,sizeof(a)),ans=n){
		for(int j=1;j<=n;++j)scanf("%d%d",&x,&y),x=x==1?14:x,++a[x];
		dfs(0),printf("%d\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/dreaming__ldx/article/details/83627443