斗地主

题目链接

1.这一版是不能拆牌的所以花色什么用都没有

2.A和2接在JQK后面存储不需要特判

3.四带的是两张单牌或者两对牌(4张)

4.顺子不带2和双王但是三带一四带二是可以带的(注意双王不算一对牌,只能算单牌)

5.当前步数最多不超过剩余牌数,minn初始化成n,每次统计剩余牌数加上step更新minn

6.有了5.单牌就不需要统计了

7.除顺子外别的牌因为牌数一定,可以算出最少步数,剪个枝

8.按牌数多少安排搜索顺序

9.当前步数大于minn直接return

#include<bits/stdc++.h>
using namespace std;
int ans=0,num[20],minn=17;
void dfs(int step)
{
	if(step>=minn) return;
	int f=0,sum=0;
	for(int i=3;i<=15;i++)
	{
		if(num[i]>0) 
		{
			f=1;
			sum+=num[i];
		}
	}
	if(num[16]>0) sum++;
	minn=min(minn,step+sum);
	if(f==0) return;
	for(int i=3;i<=14;i++)//3顺子 
	{
		int j=i;
		for(;j<=14;j++)	if(num[j]<3) break;
		j--;//j跳出来一定是不合法的,不管是>14还是num[j]<3,下同
		for(int jj=j;jj>=i+1;jj--)
		{
			for(int k=i;k<=jj;k++) num[k]-=3;
			dfs(step+1);
			for(int k=i;k<=jj;k++) num[k]+=3;
		}
	}
	for(int i=3;i<=14;i++)//2顺子 
	{
		int j=i;
		for(;j<=14;j++)	if(num[j]<2) break;
		j--;
		for(int jj=j;jj>=i+2;jj--)
		{
			for(int k=i;k<=jj;k++) num[k]-=2;
			dfs(step+1);
			for(int k=i;k<=jj;k++) num[k]+=2;
		}
	}
	for(int i=3;i<=14;i++)//单顺子 
	{
		int j=i;
		for(;j<=14;j++)	if(num[j]<1) break;
		j--;
		for(int jj=j;jj>=i+4;jj--)
		{
			for(int k=i;k<=jj;k++) num[k]--;
			dfs(step+1);
			for(int k=i;k<=jj;k++) num[k]++;
		}
	}
	if(step+sum/8>minn) return;
	for(int i=3;i<=15;i++)//4带2 ,炸弹 
	{
		if(num[i]==4)
		{
			num[i]-=4;
			for(int j=3;j<=16;j++)//带单 
			{
				if(num[j]>0)
				for(int k=3;k<=16;k++)
				{
				 	if(num[k]>0&&k!=j)//带两单 
					{
						num[j]--;num[k]--;
						dfs(step+1);
						num[j]++;num[k]++;
					}
				} 
				if(num[j]>=2)
				{
					num[j]-=2;
					dfs(step+1);
					num[j]+=2;
				}
			}
			for(int j=3;j<=15;j++)//带双 
			{
				if(num[j]>=2)
				for(int k=3;k<=15;k++)
				if(num[k]>=2&&k!=j)
				{
					num[j]-=2;num[k]-=2;
					dfs(step+1);
					num[j]+=2;num[k]+=2;
				}
			}
			dfs(step+1);//炸弹 
			num[i]+=4;
		}
	}
	if(step+sum/5>minn) return;
	for(int i=3;i<=15;i++)//3带2 ,3带1 ,3张牌 
	{
		if(num[i]==3)
		{
			num[i]-=3;
			for(int j=3;j<=15;j++)
			{
				if(num[j]>=2)
				{
					num[j]-=2;
					dfs(step+1);
					num[j]+=2;
				}
				if(num[j]>0)
				{
					num[j]--;
					dfs(step+1);
					num[j]++;
				}
			}
			if(num[16]>0)
			{
				num[16]--;
				dfs(step+1);
				num[16]++;
			}
			dfs(step+1);
			num[i]+=3;
		}
	}
	if(step+sum/2>minn) return;
	for(int i=3;i<=15;i++)//对子 
	{
		if(num[i]>=2)
		{
			num[i]-=2;
			dfs(step+1);
			num[i]+=2;
		}
	}
}
int main()
{
	int t,n;
	cin>>t>>n;
	while(t--)
	{
		memset(num,0,sizeof(num));
		ans=0;	int a1,b1;
		minn=n;
		for(int i=1;i<=n;i++)
		{
			cin>>a1>>b1;
			if(a1==0) num[16]++;
			if(a1==1) num[14]++;
			if(a1==2) num[15]++;
			if(a1>=3&&a1<=13) num[a1]++;
		}
		dfs(0);
		cout<<ans+minn<<"\n";
	}
	return 0;
}//今天是个好日子啊我的斗地主调出来了
posted @ 2020-09-15 15:02  zlq,  阅读(142)  评论(0)    收藏  举报