NOIP 2015 Day1T3 斗地主

      暴力不解释,数据随机生成,我们可以贪心的按打出牌的数量从多到少出,那么这样就能够使最优化剪枝起到很重要的作用,怎样简化代码呢?我从题解中发现了一种将单顺子,双顺子和三顺子合成一种的方法,具体实现看代码,另外我们不要考虑一种牌一下出1--4张的情况,因为如果我们把其他情况考虑完后,剩下多少种牌就要出几次,这样的话代码量就会减少一部分。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int cnt[17],T,n,ans=100;
int flag[15];
const int sz[4]={0,5,3,2};

void dfs(int x)
{
	if (x>ans) return;
	for (int i=3;i>=1;i--) 
	{
		int l=0;
		if (i==1) 
		{
			int b=5;
		}
		for (int j=3;j<=14;j++) 
		{
			if (cnt[j]<i) l=0;else l++;
			if (l>=sz[i]) 
			{
				for (int k=j;k>j-l;k--) cnt[k]-=i;
				dfs(x+1);
				for (int k=j;k>j-l;k--) cnt[k]+=i;	
			}
		}
	}
	for (int i=2;i<=14;i++)
	{
		if (cnt[i]>=4) 
		{
			cnt[i]-=4;
			for (int j=2;j<=14;j++)
			{ 
				if (j==i||cnt[j]<2) continue;
				cnt[j]-=2;
				for (int k=2;k<=14;k++) 
				{
					if (k==j||cnt[k]<2) continue;
					cnt[k]-=2;
					dfs(x+1);
					cnt[k]+=2;	
				}
				cnt[j]+=2;
			}
			for (int j=2;j<=15;j++)
			{ 
				if (j==i||cnt[j]<1) continue;
				cnt[j]-=1;
				for (int k=2;k<=15;k++) 
				{
					if (k==j||cnt[k]<1) continue;
					cnt[k]-=1;
					dfs(x+1);
					cnt[k]+=1;	
				}
				cnt[j]+=1;
			}
			cnt[i]+=4;
		}
	}
	for (int i=2;i<=14;i++) 
	{
		if (cnt[i]>=3) 
		{
			cnt[i]-=3;
			for (int j=2;j<=14;j++) 
			{
				if (i==j||cnt[j]<2) continue;
				cnt[j]-=2;
				dfs(x+1);
				cnt[j]+=2;	
			}
			for (int j=2;j<=15;j++) 
			{
				if (i==j||cnt[j]<1) continue;
				cnt[j]-=1;
				dfs(x+1);
				cnt[j]+=1;	
			}
			cnt[i]+=3;
		}
	}
	for (int i=2;i<=15;i++) 
		if (cnt[i]>0) x++;
	ans=min(ans,x);
}

int main()
{
	scanf("%d%d",&T,&n);
	while (T--) 
	{
		memset(cnt,0,sizeof cnt);
		ans=100;
		for (int i=1;i<=n;i++)
		{
			int s;
			scanf("%d",&s);
			if (s==0) cnt[15]++;else cnt[s]++;	
			scanf("%d",&s);	
		}
		cnt[14]=cnt[1];
		dfs(0);
		printf("%d\n",ans);
	}
	return 0;
}
	


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值