题目描述
牛牛最近迷上了一种叫斗地主的扑克游戏。斗地主是一种使用黑桃、红心、梅花、方片的A到K加上大小王的共54张牌来进行的扑克牌游戏。在斗地主中,牌的大小关系根据牌的数码表示如下:3<4<5<6<7<8<9<10< J< Q< K< A< 2<小王<大王,而花色并不对牌的大小产生影响。每一局游戏中,一副手牌由n张牌组成。游戏者每次可以根据规定的牌型进行出牌,首先打光自己的手牌一方取得游戏的胜利。
现在,牛牛只想知道,对于自己的若干组手牌,分别最少需要多少次出牌可以将它们打光。请你帮他解决这个问题。
需要注意的是,本题中游戏者每次可以出手的牌型与一般的斗地主相似而略有不同。
具体规则如下:
输入输出格式 输入格式:
第一行包含用空格隔开的2个正整数Tn,表示手牌的组数以及每组手牌的张数。
接下来T组数据,每组数据n行,每行一个非负整数对aibi表示一张牌,其中ai示牌的数码,bi表示牌的花色,中间用空格隔开。特别的,我们用1来表示数码A,11表示数码J,12表示数码Q,13表示数码K;黑桃、红心、梅花、方片分别用1-4来表示;小王的表示方法为01,大王的表示方法为02。
输出格式:
共T行,每行一个整数,表示打光第i手牌的最少次数。
可以把所有的出法分成两种,顺子和单独出的。
注意到出牌的顺序是没有关系的,所以可以人为规定顺序。
先暴力搜索顺子,然后可以对每种状态简单地计算出剩下的不出顺子的出法。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int oo=0x3f3f3f3f;
int num[20],cnt[5],n,ans;
void fin(int now)
{
memset(cnt,0,sizeof(cnt));
for (int i=3;i<=16;i++)
if (num[i])
{
if (num[i]<3) cnt[2]++;
else cnt[num[i]]++;
}
ans=min(ans,now+cnt[3]+cnt[4]+max(cnt[2]-cnt[3]-cnt[4]*2,0));
}
void dfs(int now)
{
fin(now);
for (register int i=3;i<=14;i++)
if (num[i])
for (register int j=i+1;j<=14&&num[j];j++)
if (j-i+1>=5)
{
for (register int k=i;k<=j;k++)
num[k]--;
dfs(now+1);
for (register int k=i;k<=j;k++)
num[k]++;
}
for (register int i=3;i<=14;i++)
if (num[i]>=2)
for (register int j=i+1;j<=14&&num[j]>=2;j++)
if (j-i+1>=3)
{
for (register int k=i;k<=j;k++)
num[k]-=2;
dfs(now+1);
for (register int k=i;k<=j;k++)
num[k]+=2;
}
for (register int i=3;i<=14;i++)
if (num[i]>=3)
for (register int j=i+1;j<=14&&num[j]>=3;j++)
{
for (register int k=i;k<=j;k++)
num[k]-=3;
dfs(now+1);
for (register int k=i;k<=j;k++)
num[k]+=3;
}
}
int main()
{
int i,j,k,x,y,z,T;
scanf("%d%d",&T,&n);
while (T--)
{
memset(num,0,sizeof(num));
for (i=1;i<=n;i++)
{
scanf("%d%d",&x,&y);
if (x==1) num[14]++;
if (x==2) num[15]++;
if (x==0) num[16]++;
if (x>=3) num[x]++;
}
ans=oo;
dfs(0);
printf("%d\n",ans);
}
}