• 【NOIP2015】斗地主(搜索,贪心)


    题面戳我

    题解

    我原来也觉得是一道不可做的难题。。
    其实,,,很简单的啦。。。
    对于当前状态
    我们出牌的方式大致分为两类
    一类是不用考虑点数的,包括单张,对子,三带一等
    另一类就是需要考虑点数的,包括顺子等

    因此,每种状态下,首先考虑不用考虑点数的出牌方法
    尝试打完,更新打完。
    搜索的作用是考虑要考虑点数的出牌方法
    每次搜索去掉若干张牌,然后递归,继续考虑不考虑点数的出牌方法。

    然后就发现这道题目特别简单啦。。。
    (还没懂就看代码吧。。。)

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    using namespace std;
    inline int read()
    {
        int x=0,t=1;char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
        if(ch=='-')t=-1,ch=getchar();
        while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
        return x*t;
    }
    int ans,N,a[20];
    void DFS(int st)
    {
        if(st>ans)return;
        int b[5];
        b[1]=b[2]=b[3]=b[4]=0;
        for(int i=1;i<=14;++i)b[a[i]]++;
        //方式1:四张带两张/对
        for(int i=1;i<=14;++i)
            if(a[i]==4)
            {
                if(b[1]>1){b[1]-=2;continue;}//带走两张单牌
                else if(b[2]>1){b[2]-=2;continue;}//带走两对牌
                else if(b[2]){b[2]--;continue;}//只能带走一对
            }
        //方式2:三张带一张/对
        for(int i=1;i<=14;++i)
        {
            if(a[i]==3)
            {
                if(b[1])b[1]--;//带一张
                else if(b[2])b[2]--;//带一对
            }
        }
        ans=min(st+b[1]+b[2]+b[3]+b[4],ans);//上面的出牌方式和ans比较
        //接下来的方式需要考虑牌的点数
        int pos;
        for(int i=1;i<=8;++i)//顺子的开始位置
        {
            pos=12;
            for(int j=i;j<13;++j)//最多打到A
            {
                a[j]--;//打出顺子
                if(a[j]==-1){pos=j;break;}//没有这么多牌呀。。。
                if(j-i>3)DFS(st+1);//打出了一个顺子
            }
            while(pos>=i)a[pos--]++;//回溯
        }
        for(int i=1;i<=10;++i)
        {
            pos=12;
            for(int j=i;j<13;++j)
            {
                a[j]-=2;
                if(a[j]<0){pos=j;break;}
                if(j-i>1)DFS(st+1);//一个双顺子
            }
            while(pos>=i)a[pos--]+=2;
        }
        for(int i=1;i<=11;++i)
        {
            pos=12;
            for(int j=i;j<13;++j)
            {
                a[j]-=3;
                if(a[j]<0){pos=j;break;}
                if(j-i)DFS(st+1);
            }
            while(pos>=i)a[pos--]+=3;
        }
    }
    int main()
    {
        int T=read();N=read();
        while(T--)
        {
            memset(a,0,sizeof(a));
            for(int i=1;i<=N;++i)
            {
                int x=read(),y=read();
                if(x==0)a[14]++;
                else if(x<3)a[x+11]++;
                else a[x-2]++;
            }
            ans=N;
            DFS(0);
            printf("%d
    ",ans);
        }
        return 0;    
    }
    
    
    
  • 相关阅读:
    Linux 用户管理命令-usermod和chage
    用户管理命令-passwd
    Linux 用户管理命令-useradd
    用户和用户组管理-用户管理相关文件
    用户和用户组管理-组信息文件
    用户和用户组管理-影子文件shadow
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
  • 原文地址:https://www.cnblogs.com/cjyyb/p/7620436.html
Copyright © 2020-2023  润新知