zoukankan      html  css  js  c++  java
  • NOIp2015D1T3 斗地主【暴搜】

    题目传送门

    刚开始读到题目的时候,非常懵逼,非常崩溃,写着写着呢,也有点崩溃,细节有点多。

    这个做法呢,只能过掉官方数据,洛谷上好像有加强版,只能得$86$分,就没有管了。

    大概说一下思路:

    暴力搜索每一种可能的情况,如果可以就递归下去,然后回溯。

    搜索框架的话,大概就是把当前搜到的出牌次数传到参数里面,如果参数已经大于了当前的最小答案就剪枝退出。然后在当前状态下枚举每一种出牌的情况,能够出就出,然后递归到下一层,参数出牌次数+1。

    可以证明不会无限递归下去,因为在参数已经大于了当前的最小答案的时候就退出了。

    可以分为三大类出牌:顺子、带牌、散牌

    还有一些细节什么的:

    1.把$A$放在$K$后面,顺子的时候比较方便

    2.$2$不能在顺子里面(当时还理解了好久$2$点是什么,还以为是什么其他代称...)

    3.王。之前以为王只可以单出或者火箭,没有认真读题,王是可以被带的,但是只能带单牌,王不能看成一对,他们牌值不一样。

    4.后来发现顺子和带牌打完之后,可以不用单独考虑打散牌(单牌,对子,三张牌),因为如果剩下,$1$次就可以打出去一种,而且无论如何只打$1$次用的打牌次数会最少。而且散牌不用考虑与其他牌的组合。(可以感性理解,次数最多肯定是每一次都按种数打散牌)

      1 #include<cstdio>
      2 #include<algorithm>
      3 #include<vector>
      4 #include<cstring>
      5 #include<queue>
      6 #include<map>
      7 #include<iostream>
      8 using namespace std;
      9 #define ll long long
     10 #define INF 0x3f3f3f3f
     11 #define N 30
     12 int rd()
     13 {
     14     int f=1,s=0;char c=getchar();
     15     while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
     16     while(c>='0'&&c<='9'){s=(s<<3)+(s<<1)+(c^48);c=getchar();}
     17     return f*s;
     18 }
     19 //J->11 Q->12 K->13 A->14 2->15 King->16 
     20 //王特殊处理 只能出火箭或者单出(糟糕 还可以单带 
     21 //2不能出顺子 
     22 int n,ans;
     23 int cnt[N];
     24 void dfs(int res)
     25 {
     26     if(res>=ans) return ;//剪枝 提前退出
     27     /*
     28     //-----炸弹
     29     for(int i=3;i<=15;i++)
     30         if(cnt[i]>=4)
     31         {
     32             cnt[i]-=4;
     33             dfs(res+1);
     34             cnt[i]+=4;
     35         }
     36     //----- 
     37     //-----对子牌
     38     for(int i=3;i<=15;i++)
     39         if(cnt[i]>=2)
     40         {//2个对子...就是炸弹了 应该在前面判断过了 
     41             cnt[i]-=2;
     42             dfs(res+1);
     43             cnt[i]+=2;
     44          } 
     45     //----- 
     46     //-----三张牌 
     47     for(int i=3;i<=15;i++)
     48         if(cnt[i]>=3)
     49         {
     50             cnt[i]-=3;
     51             dfs(res+1);
     52             cnt[i]+=3;
     53          }
     54     //----- 
     55     */
     56     //-----顺子
     57     //---单顺子 
     58     int k=0;
     59     for(int i=3;i<=14;i++)//不包括2点 
     60     {
     61         if(cnt[i]==0) k=0;//顺子断了 从这里重新开始
     62         else//否则就接下去
     63         {
     64             k++;
     65             if(k>=5)
     66             {
     67                 for(int j=i;j>=i-k+1;j--)
     68                     cnt[j]--;
     69                 dfs(res+1);
     70                 for(int j=i;j>=i-k+1;j--)
     71                     cnt[j]++;
     72             }
     73         }
     74     } 
     75     //--- 
     76     //---双顺子 
     77     k=0;
     78     for(int i=3;i<=14;i++)//不包括2点
     79     {
     80         if(cnt[i]<2) k=0;//顺子断了 从这里重新开始
     81         else//否则就接下去 
     82         {
     83             k++;
     84             if(k>=3)
     85             {
     86                 for(int j=i;j>=i-k+1;j--)
     87                     cnt[j]-=2;
     88                 dfs(res+1);
     89                 for(int j=i;j>=i-k+1;j--)
     90                     cnt[j]+=2;
     91             }
     92         }
     93     }
     94     //---
     95     //---三顺子
     96     k=0;
     97     for(int i=3;i<=14;i++)//不包括2点
     98     {
     99         if(cnt[i]<3) k=0;//顺子断了 从这里重新开始
    100         else//否则就接下去 
    101         {
    102             k++;
    103             if(k>=2)
    104             {
    105                 for(int j=i;j>=i-k+1;j--)
    106                     cnt[j]-=3;
    107                 dfs(res+1);
    108                 for(int j=i;j>=i-k+1;j--)
    109                     cnt[j]+=3;
    110             }
    111         }
    112     }
    113     //--- 
    114     //-----
    115     //-----带牌
    116     for(int i=3;i<=15;i++)
    117     {
    118         if(cnt[i]<3) continue;
    119         //3带X 
    120         cnt[i]-=3;
    121         for(int j=3;j<=16;j++)
    122         {
    123             if(i==j) continue;
    124             if(cnt[j]>=1)
    125             {
    126                 cnt[j]--;
    127                 dfs(res+1);
    128                 cnt[j]++;
    129             }
    130             if(cnt[j]>=2&&j!=16/*王不能一起带*/)
    131             {
    132                 cnt[j]-=2;
    133                 dfs(res+1);
    134                 cnt[j]+=2;
    135             }
    136         }
    137         cnt[i]+=3;
    138         //4带X(两个单张或两个对)
    139         if(cnt[i]<4) continue;
    140         cnt[i]-=4;
    141         for(int j=3;j<=16;j++)
    142         {
    143             if(i==j||cnt[j]<=0) continue;
    144             cnt[j]--;//两张单牌 
    145             for(int k=3;k<=16;k++)
    146             {
    147                 if(k==j||k==i||cnt[k]<1) continue;
    148                 cnt[k]--;
    149                 dfs(res+1);
    150                 cnt[k]++; 
    151             }
    152             cnt[j]++;
    153             if(cnt[j]<2||j==16/*王不能一起*/) continue; 
    154             cnt[j]-=2;//两对对子
    155             for(int k=3;k<=15;k++)
    156             {
    157                 if(k==j||k==i||cnt[k]<2) continue;
    158                 cnt[k]-=2;
    159                 dfs(res+1);
    160                 cnt[k]+=2;
    161             } 
    162             cnt[j]+=2;
    163         }
    164         cnt[i]+=4;
    165      }
    166     //----- 
    167     for(int i=3;i<=16;i++)
    168         if(cnt[i]) res++;
    169     //突然发现 单张 对子三张都不用特殊考虑 反正能一次出完剩下的所有牌 
    170     ans=min(ans,res);
    171 }
    172 int main() 
    173 {
    174     int T=rd(),n=rd();
    175     while(T--)
    176     {
    177         memset(cnt,0,sizeof(cnt));
    178         ans=INF;
    179         for(int i=1;i<=n;i++)
    180         {
    181             int m=rd(),opt=rd();
    182             if(m==0) m=16;
    183             if(m==1) m=14;
    184             if(m==2) m=15;
    185             cnt[m]++;
    186         }
    187         dfs(0);
    188         printf("%d
    ",ans);
    189     }
    190     return 0;
    191 }
    Code
  • 相关阅读:
    基于微软解决方案的负载测试实现知识库1____(转)理解.NET中的数据库连接池
    [转] Performance vs. load vs. stress testing _Grig Gheorghiu (翻译水平有限,如有错误请帮忙刊正)
    Bill Gates Centimillionaire and one poor man.
    VB Comwrapper 的实现
    使用接口作为返回值
    如何排查SQL死锁的错误?
    VC++动态链接库编程之DLL典型实例
    VC++动态链接库编程之DLL木马
    VC中获取窗口句柄的各种方法 .
    VC++动态链接库编程之MFC扩展 DLL
  • 原文地址:https://www.cnblogs.com/lyttt/p/11832122.html
Copyright © 2011-2022 走看看