QAQ
15的搜索题目,加优化剪枝,A掉啦
首先我们把A存到a[12],把2存到a[13]中,这样处理顺子比较好处理
如果有四张的牌
首先我们肯定是带两张单牌比较优
然后是带两个对子优,之后是一个对子
因为对子组成顺子比单牌容易,所以优先搞单牌
三张的类似
然后枚举三种顺子
逐一枚举各种方案,去找最优解
因为顺子并不是越长越好的,打过斗地主的都知道吧
一个可行性剪枝是当现在的出牌的次数大于当前最优的方案就直接返回,不知道会快多少呢
每次的ans的初始值为23,因为最多的数据只有23张手牌,没有答案会比23大啦
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int t,n;
int ans;
int a[16];
void in()
{
memset(a,0,sizeof(a));//每次清零
for(int i=1;i<=n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
if(x==0)
a[14]++;
if(x==1)
a[12]++;
if(x==2)
a[13]++;
if(x>=3)
a[x-2]++;
}
}
void dfs(int x)
{
if(x>ans) return;
int s1,s2,s3,s4;
s1=s2=s3=s4=0;
for(int i=1;i<=14;i++)//统计单牌与对子
{
if(a[i]==1) s1++;
if(a[i]==2) s2++;
}
for(int i=1;i<=14;i++)//四带的牌
if(a[i]==4)
{
s4++;
if(s1>=2) s1-=2;
else if(s2>=2) s2-=2;
else if(s2>=1) s2--;
}
for(int i=1;i<=14;i++)//三带的牌
if(a[i]==3)
{
s3++;
if(s1>=1) s1--;
else if(s2>=1) s2--;
}
ans=min(ans,x+s1+s2+s3+s4);//手中没牌,更新方案
int j;
for(int i=1;i<=8;i++)//枚举单顺子,第一层枚举起点,第二层枚举长度
{
for(j=i;j<=12;j++)
{
a[j]--;
if(a[j]<0) break;
if(j-i>=4) dfs(x+1);
}
if(j==13) j--;
while(j>=i) a[j--]++;//回溯过程
}
for(int i=1;i<=10;i++)//枚举双顺子
{
for(j=i;j<=12;j++)
{
a[j]-=2;
if(a[j]<0) break;
if(j-i>=2) dfs(x+1);
}
if(j==13) j--;
while(j>=i) a[j--]+=2;
}
for(int i=1;i<=11;i++)//枚举三顺子
{
for(j=i;j<=12;j++)
{
a[j]-=3;
if(a[j]<0) break;
if(j-i>=1) dfs(x+1);
}
if(j==13) j--;
while(j>=i) a[j--]+=3;
}
}
int main()
{
scanf("%d%d",&t,&n);
while(t--)
{
in();
ans=23;
dfs(0);
printf("%d\n",ans);
}
return 0;
}