zoukankan      html  css  js  c++  java
  • 洛谷 2540 斗地主增强版

    Description

    牛牛最近迷上了一种叫斗地主的扑克游戏。斗地主是一种使用黑桃、红心、梅花、方片的A到K加上大小王的共54张牌来进行的扑克牌游戏。在斗地主中,牌的大小关系根据牌的数码表示如下:3<4<5<6<7<8<9<10<J<Q<K<A<2<小王<大王,而花色并不对牌的大小产生影响。每一局游戏中,一副手牌由n张牌组成。游戏者每次可以根据规定的牌型进行出牌,首先打光自己的手牌一方取得游戏的胜利。

    现在,牛牛只想知道,对于自己的若干组手牌,分别最少需要多少次出牌可以将它们打光。请你帮他解决这个问题。

    需要注意的是,本题中游戏者每次可以出手的牌型与一般的斗地主相似而略有不同。

    具体规则如下:

    在此题中认为两个王不能组成对子牌

    Input

    第一行包含用空格隔开的2个正整数T和n,表示手牌的组数以及每组手牌的张数。

    接下来T组数据,每组数据n行,每行一个非负整数对aibi表示一张牌,其中ai示牌的数码,bi表示牌的花色,中间用空格隔开。特别的,我们用1来表示数码A,11表示数码J,12表示数码Q,13表示数码K;黑桃、红心、梅花、方片分别用1-4来表示;小王的表示方法为01,大王的表示方法为02。

     Output

    共T行,每行一个整数,表示打光第i手牌的最少次数。

    Sample

    输入样例#1:
    1 8
    7 4
    8 4
    9 1
    10 4
    11 1
    5 1
    1 4
    1 1
    输出样例#1:
    3
    输入样例#2:
    1 17
    12 3
    4 3
    2 3
    5 4
    10 2
    3 3
    12 2
    0 1
    1 3
    10 1
    6 2
    12 1
    11 3
    5 2
    12 4
    2 2
    7 2
    输出样例#2:
    6

    Hints

    样例1说明

    共有1组手牌,包含8张牌:方片7,方片8,黑桃9,方片10,黑桃J,黑桃5,方片A以及黑桃A。可以通过打单顺子(方片7,方片8,黑桃9,方片10,黑桃J),单张牌(黑桃5)以及对子牌(黑桃A以及方片A)在3次内打光。

    对于前20个测试点, 我们约定手牌组数T与张数n的规模如下:

    数据不保证所有的手牌都是随机生成的。

     

    好像很早就听说这道神奇的题了,我以为这是一道像模拟的搜索题,就开始傻傻地模拟,但是难过地发现样例就超时了

    T了很久,去看了题解,题解是搜索+贪心,打了一会儿,De了很久的bug,终于过了,写题解的时候想不通那个贪心,想了很久,后来终于发现那个贪心有bug

    出完顺子以后,不能直接得出答案,因为有些4,3什么的可以拆一下,但是不同情况下的拆法不一样

    好像写了4,5个版本,写得要疯掉了●︿●

    我发现了自己为什么要T,其实是搜索的时候重复了,确定出牌方法以后,顺序就没有影响了,所以每次枚举的时候不需要把所有出牌方法都搜一遍

    Solution

    搜索的时候状态不能重复,要按照某一个顺序

    ✿按照牌的大小顺序搜索

       枚举当前这种类型牌以什么形式出

       如果是顺子,那么以当前牌为起点,往后找是否能构成顺子

       三带二...什么的,可以先不枚举带的那张(对)牌,先记录一下,单牌,对子,三张牌,四张牌各出了多少次,到最后再处理,这样就可以只枚举一种牌一次出几张(优化一下,变成把一个数拆分成什么,因为2总是优于2个1,所以不考虑把2拆成1)

       (为4分配2,1,为3分配...什么的,处理的时候,优先为4找两单,两双,一双(相当于两单),然后为3找一单,一双,在答案里减去)

       (注意一种牌可能会分几次被出出去,所以如果一次出牌后,还没有出完,下一次要继续搜索这一种牌)

    ✿按照出牌的顺序出

       我没有用这种方法写过,看到有大佬写了,跑得有点慢

       每次枚举一种类型的时候,如果互不相关的话,只搜一个(因为答案跟出牌顺序无关),举个栗子,枚举顺子的话,只找到第一个最长的顺子,然后枚举长度,保证与这个顺子相关的顺子都考虑到了,而无关的顺子不需要管,下一次也可以被枚举到

      枚举其它牌的方法同上,一个剪枝,如果剩下的单牌,对子什么的可以被出过的三张牌,四张牌带走,就不用往下搜了,直接更新答案

    注意细节

    比如,大王小王特殊处理

              不要把四带两对看成四带一对了

     

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    #define inf 100000001
    using namespace std;
    int pai[21],use[6],res=inf;
    int read()
    {
        int ans=0,f=1;char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)) {ans=ans*10+ch-'0';ch=getchar();}
        return ans*f;
    }
    void search(int th,int v)
    {
        if(th>14)
        {
            int ne=v,a=use[1],b=use[2],c=use[3],d=use[4];
    		if(a==2&&b==1&&c==1&&d==1)
    		{
    			int debug=1;
    		}
            if(d>=(a>>1))
              ne-=(a>>1)<<1,d-=(a>>1),a&=1;
            else
              ne-=d<<1,a-=d<<1,d=0;
            if(d>=(b>>1))
              ne-=(b>>1)<<1,d-=(b>>1),b&=1;
            else
              ne-=d<<1,b-=d<<1,d=0;
            if(d>=b)
              ne-=b,d-=b,b=0;
            if(c>=a)
              ne-=a,c-=a,a=0;
            else
              ne-=c,a-=c,c=0;
            if(c>=b)
              ne-=b,c-=b,b=0;
            else
              ne-=c,b-=c,c=0;
            res=ne<res? ne:res;
            return;
        }
        if(!pai[th])
        {
            search(th+1,v);
    		return;
        }
        int now=-1;
        if(th>=3)        //顺子
        {
            for(int i=th;i<=14;i++)
            {
                if(pai[i]<3) break;
                now=i;
                pai[i]-=3;
                if(i-th+1>=2)
                  search(th,v+1);
            }
            for(int i=th;i<=now;i++)
              pai[i]+=3;
            now=-1;             //////////
            for(int i=th;i<=14;i++)
            {
                if(pai[i]<2) break;
                now=i;
                pai[i]-=2;
                if(i-th+1>=3)
                  search(th,v+1);
            }
            for(int i=th;i<=now;i++)
              pai[i]+=2;
            now=-1;
            for(int i=th;i<=14;i++)
            {
                if(!pai[i]) break;
                now=i;
                pai[i]--;
                if(i-th+1>=5)
                  search(th,v+1);
            }
            for(int i=th;i<=now;i++)
              pai[i]++;
        }
        if(pai[th]==4)
        {
            pai[th]-=4;
    		use[4]++;search(th+1,v+1);use[4]--;
    		use[3]++;use[1]++;search(th+1,v+2);use[3]--;use[1]--;
    		use[2]+=2;search(th+1,v+2);use[2]-=2;
    		pai[th]+=4;
        }
        else if(pai[th]==3)
        {
            pai[th]-=3;
            use[3]++;search(th+1,v+1);use[3]--;
            use[2]++;use[1]++;search(th+1,v+2);use[2]--;use[1]--;       //相当于出了两次,v要+2
            pai[th]+=3;
        }
        else if(pai[th]==2)
        {
            pai[th]-=2;
            use[2]++;search(th+1,v+1);use[2]--;
            pai[th]+=2;
        }
        else if(pai[th]==1)
        {
            pai[th]--;
            use[1]++;search(th+1,v+1);use[1]--;
            pai[th]++;
        }
    }
    int main()
    {
    //	freopen("testdata21.in","r",stdin);
    //	freopen("wo.out","w",stdout);
        int t,n,num,co;
        t=read();n=read();
        for(int j=1;j<=t;j++)
        {
            if(j==13)
            {
                int debug=1;
            }
            res=inf;
            memset(pai,0,sizeof(pai));            //傻傻忘清零 
            memset(use,0,sizeof(use));            //
            for(int i=1;i<=n;i++)
            {
                num=read();co=read();
                if(num==1)
                  pai[14]++;
                else if(num==0)
                  pai[co-1]++;
                else
                    pai[num]++;
            }
            if(pai[0]&&pai[1])
            {
            	pai[0]--,pai[1]--,search(2,1);      //不能放在
            	pai[0]++,pai[1]++,search(0,0);      //
            }
            else
              search(0,0);
            printf("%d
    ",res);
        }
        return 0;
    }
    /*
    1 10
    1 1
    1 1
    1 1
    1 1
    3 1
    3 1
    3 1
    5 1
    5 1
    7 1
    */
  • 相关阅读:
    阅读prettytable 一些代码、get、set 检查参数
    python 库 PrettyTabble 使用与错误
    python 内建模块与第三方模块
    python 排序 堆排序
    python 排序 桶排序
    python 排序冒泡排序与双向冒泡排序
    python 函数式编程 闭包,返回一个函数
    python 排序 选择排序
    python 排序 归并排序
    python 排序 插入排序与希尔排序
  • 原文地址:https://www.cnblogs.com/charlotte-o/p/7652320.html
Copyright © 2011-2022 走看看