【NOIP2015】洛谷2668 斗地主

36 篇文章 0 订阅
23 篇文章 0 订阅

题目描述

牛牛最近迷上了一种叫斗地主的扑克游戏。斗地主是一种使用黑桃、红心、梅花、方片的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);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值