• 题解 P2668 【斗地主】


    dfs+简易剪枝+简易a*

    思路:

    dfs+简易剪枝+简易a(我也不知道算不算a);

    dfs参数记录层数

    按消耗牌多少的贪心顺序搜索

    有几种情况可以不用搜索(但我还是搜索了)

    可以用a*估算出来

    最后剩下有单牌,对子,三张牌,4炸弹的时候可以直接算出来;

    还有一个剪枝,一个简简单单的剪枝(if(x>=ans) return;);

    这个因为省略了很多情况所以并不很慢;

    反正我是过了;

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    using namespace std;
    int n,jk,kl,ai,bi,hand[20],ans=0x7fffffff;
    int t,c[10];
    int A_star() {
        memset(c,0,sizeof(c));
        int tot=0,kll=0;
        for(int i=1; i<=15; i++) c[hand[i]]++; //统计当前还剩的牌数
        while(c[4]&&c[2]>1) c[4]--,c[2]-=2,tot++;//四带一对
        while(c[4]&&c[1]>1) c[4]--,c[1]-=2,tot++;//四带两单
        while(c[3]&&c[2]) c[3]--,c[2]--,tot++;//三带二
        while(c[3]&&c[1]) c[3]--,c[1]--,tot++;//三带一
        for(int i=1; i<=9; i++) kll+=c[i];
        return tot+kll;//带牌+三张 对子 单张
    }
    void dfs(int x) {
    //    num=min(num,ans);
    //  printf("%d %d  ",x,ans);
    //  for(int i=1;i<=15;i++) printf("%d ",hand[i]);
    //  printf("\n");
        if(x>=ans) return;
        int pd=0;
        int cur=0;
    
        for(int i=1; i<=13; i++) { //四带两对
            if(hand[i]>=4) {
                hand[i]-=4;
                for(int j=1; j<=13; j++) {
                    if(j!=i&&hand[j]>=2) {
                        hand[j]-=2;
                        for(int v=1; v<=13; v++) {
                            if(hand[v]>=2&&v!=j) {
                                hand[v]-=2;
    //                           printf("1 ");
                                dfs(x+1);
                                hand[v]+=2;
                            }
                        }
                        hand[j]+=2;
                    }
                }
                hand[i]+=4;
            }
        }
        for(int i=1; i<=13; i++) { //四带二单
            if(hand[i]>=4) {
                hand[i]-=4;
                for(int j=1; j<=13; j++) {
                    if(j!=i&&hand[j]>=1) {
                        hand[j]-=1;
                        for(int v=1; v<=13; v++) {
                            if(hand[v]>=1&&v!=i) {
                                hand[v]-=1;
    ///                           printf("2 ");
                                dfs(x+1);
                                hand[v]+=1;
                            }
                        }
                        hand[j]+=1;
                    }
                }
                hand[i]+=4;
            }
        }
        for(int i=1; i<=11; i++) { //三顺
            cur=0;
            if(hand[i]>=3&&i<=11) {
                for(int j=i; j<=12; j++) {
                    if(hand[j]>=3) cur++;
                    else break;
                }
                for(int j=cur; j>=2; j--) {
                    for(int v=i; v<=j+i-1; v++) hand[v]-=3;
                    //            printf("3 ");
                    dfs(x+1);
                    for(int v=i; v<=j+i-1; v++) hand[v]+=3;
                }
            }
        }
        for(int i=1; i<=10; i++) { //二顺
            cur=0;
            if(hand[i]>=2&&i<=10) {
                for(int j=i; j<=12; j++) {
                    if(hand[j]>=2) cur++;
                    else break;
                }
                for(int j=cur; j>=3; j--) {
                    for(int v=i; v<=j+i-1; v++) hand[v]-=2;
                    //  printf("4 ");
                    dfs(x+1);
                    for(int v=i; v<=j+i-1; v++) hand[v]+=2;
                }
            }
        }
        for(int i=1; i<=8; i++) { //一顺
            cur=0;
            if(hand[i]>=1&&i<=8) {
                for(int j=i; j<=12; j++) {
                    if(hand[j]>=1) cur++;
                    else break;
                }
                for(int j=cur; j>=5; j--) {
                    for(int v=i; v<=j+i-1; v++) hand[v]-=1;
                    //    printf("5 ");
                    dfs(x+1);
                    for(int v=i; v<=j+i-1; v++) hand[v]+=1;
                }
            }
        }
        for(int i=1; i<=13; i++) { //三带二
            if(hand[i]>=3) {
                hand[i]-=3;
                for(int j=1; j<=13; j++) {
                    if(j!=i&&hand[j]>=2) {
                        hand[j]-=2;
                        //       printf("6 ");
                        dfs(x+1);
                        hand[j]+=2;
                    }
                }
                hand[i]+=3;
            }
        }
        for(int i=1; i<=13; i++) { //三带一
            if(hand[i]>=3) {
                hand[i]-=3;
                for(int j=1; j<=15; j++) {
                    if(j!=i&&hand[j]>=1) {
                        hand[j]-=1;
                        //         printf("7 ");
                        dfs(x+1);
                        hand[j]+=1;
                    }
                }
                hand[i]+=3;
            }
        }
        if(hand[14]>=1&&hand[15]>=1) {
            hand[14]--;
            hand[15]--;
            //  printf("8 ");
            dfs(x+1);
            hand[14]++;
            hand[15]++;
        }
        jk=A_star();
        if(x+jk>=ans) return;
        else ans=x+jk;
    }
    
    int main() {
        scanf("%d%d",&t,&n);
        while(t--) {
            memset(hand,0,sizeof(hand));
            ans=0x7fffffff;
            for(int i=1; i<=n; i++) {
                cin>>ai>>bi;
                if(ai!=0) {
                    if(ai>=3) hand[ai-2]++;
                    else hand[11+ai]++;
                } else {
                    if(bi==1) hand[14]++;
                    else hand[15]++;
                }
            }
            // for(int i=1;i<=15;i++) printf("%d ",hand[i]);
            //    printf("\n");
            dfs(0);
            printf("%d\n",ans);
        }
        return 0;
    }
    View Code

    斗地主,感觉写完这个代码我都成了斗地主大神了。

  • 相关阅读:
    《Attack ML Models
    对抗攻击基础知识(完结)
    解决github release下载慢/下载失败的问题
    《Effective Python:编写高质量Python代码的59个有效方法》读书笔记(完结)
    MacBook常用软件
    解决python3读写中文txt时UnicodeDecodeError : 'ascii' codec can't decode byte 0xc4 in position 5595: ordinal not in range(128) on line 0的问题
    Shell中的函数库
    Mysql登录报1045错误
    宝塔面板关键目录解析
    CentOS7 yum报 Cannot retrieve metalink for repository: epel/x86_64. Please verify its path解决方法
  • 原文地址:https://www.cnblogs.com/Xchu/p/11355885.html
Copyright © 2020-2023  润新知