现在给你n张牌,只能按照斗地主的规则出牌,规则如下:
王炸
一张单牌
一对牌
三张相同单牌
炸弹
顺子(不包括王和2,与斗地主相同需要连续至少5种)
双顺(即每种两张,至少连续3种,不包括王和2)
三顺(即每种三张,至少连续2种,不包括王和2)
三带一单
三带一对
四带两单
四带王炸
四带一对
四带两对
两个炸弹
我们可以使用dfs来做此题。
首先,我们知道ans最多为14,我们加ans优化,即当前答案大于等于ans就退出。
我们发现,调转出牌次序没有影响,因此我们要避免同一种出牌方案被再次访问。
我们可以率先从耗牌多的开始,来辅助ans优化。
因此,我们可以按照三顺-双顺-顺-四带-三带的次序来做,这些都做完后,可知有多少种就还需多少次出牌。
王炸应在一开始特判,大王小王应当不同码数的牌来算,避免出现三带王炸和四带王炸带对。
做顺时,可以找出每一段最长l~r使得这个区间能顺,然后根据长度做到底怎么打出去这个顺。
我们发现,做带时牌的码数已经无用,我们可以用p[i]表示还剩i张的有多少种进行优化。
这样就能过,注意细节,很容易打挂!
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
int a[20],p[7];
int i,j,k,l,t,n,m,ans,ca,gjx,wzd;
void solve2(int y){
if (y+15-p[0]<ans) ans=y+15-p[0];
if (y>=ans) return;
int i,j;
if (p[4]>=1){
fo(i,2,4)
fo(j,2,4){
if ((i==j&&p[i]>=2)||(i!=j&&p[i]&&p[j])){
if (i==4&&j!=i&&p[4]<2) continue;
else if (i==4&&j==i&&p[4]<3) continue;
else if (i!=4&&j==4&&p[4]<2) continue;
p[4]--;p[0]++;p[i]--;p[i-2]++;p[j]--;p[j-2]++;
solve2(y+1);
p[4]++;p[0]--;p[i]++;p[i-2]--;p[j]++;p[j-2]--;
}
}
fo(i,1,4)
fo(j,1,4){
if ((i==j&&p[i]>=2)||(i!=j&&p[i]&&p[j])){
if (i==4&&j!=i&&p[4]<2) continue;
else if (i==4&&j==i&&p[4]<3) continue;
else if (i!=4&&j==4&&p[4]<2) continue;
p[4]--;p[0]++;p[i]--;p[i-1]++;p[j]--;p[j-1]++;
solve2(y+1);
p[4]++;p[0]--;p[i]++;p[i-1]--;p[j]++;p[j-1]--;
}
}
fo(i,2,4){
if (i==4&&p[4]<2) continue;
if (p[i]<1) continue;
p[4]--;p[0]++;p[i]--;p[i-2]++;
solve2(y+1);
p[4]++;p[0]--;p[i]++;p[i-2]--;
}
}
if (p[3]>=1){
fo(i,2,4){
if (i==3&&p[3]<2) continue;
if (p[i]<1) continue;
p[3]--;p[0]++;p[i]--;p[i-2]++;
solve2(y+1);
p[3]++;p[0]--;p[i]++;p[i-2]--;
}
fo(i,1,4){
if (i==3&&p[3]<2) continue;
if (p[i]<1) continue;
p[3]--;p[0]++;p[i]--;p[i-1]++;
solve2(y+1);
p[3]++;p[0]--;p[i]++;p[i-1]--;
}
}
if (p[4]>=1){
fo(i,2,4){
if (i==4&&p[4]<2) continue;
if (p[i]<1) continue;
p[4]--;p[1]++;p[i]--;p[i-2]++;
solve2(y+1);
p[4]++;p[1]--;p[i]++;p[i-2]--;
}
fo(i,1,4){
if (i==4&&p[4]<2) continue;
if (p[i]<1) continue;
p[4]--;p[1]++;p[i]--;p[i-1]++;
solve2(y+1);
p[4]++;p[1]--;p[i]++;p[i-1]--;
}
}
if (p[4]>=2){
p[4]-=2;p[0]+=2;
solve2(y+1);
p[4]+=2;p[0]-=2;
}
}
void solve1(int y){
if (y>=ans) return;
int i,j,l=1,r;
fill(p,p+5,0);
fo(i,1,15) p[a[i]]++;
if (p[0]==15){
ans=y;
return;
}
solve2(y);
fo(i,1,13){
if (a[i]<3||i==13){
while (1){
r=i-1;
if (l>r||l==r){
l=i+1;
break;
}
fo(j,l,r) a[j]-=3;
fd(j,r,l+1){
solve1(y+1);
a[j]+=3;
}
a[l]+=3;
l++;
}
}
}
l=1;
fo(i,1,13){
if (a[i]<2||i==13){
while (1){
r=i-1;
if (l>r||r-l<2){
l=i+1;
break;
}
fo(j,l,r) a[j]-=2;
fd(j,r,l+2){
solve1(y+1);
a[j]+=2;
}
a[l]+=2;a[l+1]+=2;
l++;
}
}
}
l=1;
fo(i,1,13){
if (a[i]<1||i==13){
while (1){
r=i-1;
if (l>r||r-l<4){
l=i+1;
break;
}
fo(j,l,r) a[j]--;
fd(j,r,l+4){
solve1(y+1);
a[j]++;
}
a[l]++;a[l+1]++;a[l+2]++;a[l+3]++;
l++;
}
}
}
}
int main(){
freopen("landlords.in","r",stdin);freopen("landlords.out","w",stdout);
scanf("%d%d",&ca,&n);
while (ca--){
fill(a+1,a+16,0);
fo(i,1,n){
scanf("%d%d",&gjx,&wzd);
if (gjx>=3&&gjx<=13) a[gjx-2]++;
else if (gjx==2) a[13]++;
else if (gjx==1) a[12]++;
else if (wzd==1) a[14]++;
else a[15]++;
}
ans=14;
if (a[14]&&a[15]){
a[14]--;a[15]--;
solve1(1);
a[14]++;a[15]++;
}
solve1(0);
printf("%d\n",ans);
}
fclose(stdin);fclose(stdout);
return 0;
}