• 斗地主算法


           不得不承认,算法搁置了一些时间,代码的风格下降了好多!  贴上一个曹点多多且丑的代码!  Orz... 

    题目要求:     

    编码:3表示3点 ,4表示4点点  。。。。 10表示10点  11表示J   12表示Q   13表示K  14表示A   15表示2   16表示小王   17表示大王

    要求:

    1)出牌牌型包括(单子,对子, 三张,三带一,三带二,顺子,连对(3连对,4连对,5连对....),四张炸弹,四带一 ,四带二(四带2个单张,四带2个对子),对王炸弹)

    2)初始化1副牌(54张),随机发一手牌(17张)显示出来

    3)手动输入一个几张牌。判断输入牌是否是1)中的牌型。 程序根据牌型判断自己的手牌是否可以压该牌,如果可以压,则显示可以压的牌型,并输出,从手牌减去已压的牌。显示剩余的牌

    4)循环过程要求3 直到牌出完。

    代码:  

      1 #define Gxjun
      2 #define LOCAL
      3 #define Test
      4 #include<stdio.h>
      5 #include<string.h>
      6 #include<stdlib.h>
      7 #include<time.h>
      8 #define Arr_Len(arr)  sizeof(arr)/sizeof(arr[0])
      9 #define maxn 18
     10 
     11 
     12 int cod[maxn]={0};
     13 int mycod[maxn];
     14 int chu[maxn];
     15 int rtmp[maxn]={0} ,mtmp[maxn]={0};
     16 int mx  , mn ;
     17 
     18 typedef struct LianD
     19 {
     20     int en ; //连对结尾的牌号
     21     int du ; //最接近的度数
     22     int cnt ; //连对的个数
     23     int tem ; //临时存储的结尾牌号
     24     //复制值函数
     25     void copfun(struct LianD  *Ld){
     26 
     27         Ld->cnt=cnt;
     28         Ld->du=du;
     29         Ld->en=en;
     30         Ld->tem=tem;
     31     }
     32     //初始化
     33     void init(){
     34       en=du=cnt=tem=0;
     35     }
     36 };
     37 
     38 enum AlgTyNn{  ShunZi=1 ,
     39                LianDui
     40              };
     41 
     42 int cmp(const void * arg  , const void * brg){
     43 
     44    int * ar =(int *) arg ;
     45    int * br =(int *) brg ;
     46    return *ar - *br ;
     47 
     48 }
     49 
     50 #ifdef Test
     51 void init()
     52 {
     53   int i , cnt=0 ;
     54 
     55 
     56 #ifdef Test
     57   #ifndef LOCAL
     58    #define LOCAL
     59    #endif // LOCAL
     60 #endif // Test
     61 
     62 #ifdef LOCAL
     63    freopen("data.in","r",stdin);
     64 #endif // Test
     65   memset(mycod , 0 , sizeof(mycod));
     66   mycod[cnt]=17;
     67   cod[17]=cod[16]=1;   //一对王
     68   for(i=3 ; i<16 ;i++)
     69       cod[i]=4;
     70   while(++cnt<maxn){
     71      scanf("%d" ,&mycod[cnt]);
     72      cod[mycod[cnt]]--;
     73  }
     74  #ifdef Gxjun
     75   fclose(stdin);
     76   freopen("CON","r",stdin);
     77   #endif // Gxjun
     78   qsort(mycod+1 , cnt-1 , sizeof(mycod-1) , cmp);
     79 }
     80 
     81 #endif // Test
     82 
     83 #ifndef Test
     84 void init(){
     85 
     86   int i , hopg ,cnt=0 ;
     87   memset( mycod , 0 , sizeof(mycod) ) ;
     88   mycod[cnt]=17;
     89   for(i=3 ; i<16 ;i++)
     90       cod[i]=4;
     91   cod[16]=1;   //一对王
     92   cod[17]=1;
     93   srand(time(NULL));
     94 
     95   while(cnt<maxn){
     96 
     97     hopg = rand()%maxn ;
     98 
     99     if( hopg>0&&cod[hopg] > 0 ){
    100       cod[hopg]--;
    101       mycod[++cnt]=hopg;
    102     }
    103   }
    104   qsort(mycod+1 , cnt-1 , sizeof(mycod-1) , cmp);
    105 
    106 }
    107 #endif // Test
    108 
    109 //对方输出
    110 void inputs(){
    111 
    112   int cnt=0;
    113   memset(chu , 0 , sizeof(chu));
    114    while(1){
    115      scanf("%d",&chu[++cnt]);
    116      if(chu[cnt]<0) break;
    117   }
    118    chu[0]=cnt-1 ;  //最开头放置纸牌的数目
    119 
    120 }
    121 
    122 //打印剩余
    123 void output(){
    124 
    125     printf("  |   剩牌系: ");
    126     //剩余牌系
    127     int cont=0;
    128     for(int j=3 ; j<maxn ;j++){
    129         cont+=mtmp[j];
    130         for(int k=0; k<mtmp[j] ; k++){
    131            printf("%d ",j);
    132         }
    133     }
    134      mtmp[0]=cont;
    135      printf("	剩牌数: [ %d ]",mtmp[0]);
    136      puts("");
    137 }
    138 
    139 //计数排序
    140 void connt(int *tmp , const int ss []){
    141 
    142    //memset(tmp ,0 ,sizeof(tmp));
    143    tmp[0]=ss[0];
    144   for(int i= 1 ; i<=ss[0] ; i++)
    145         tmp[ss[i]]++;     //计数排序
    146 }
    147 
    148 //判断是否有炸弹或者王炸
    149 void ZhaDan(){
    150 
    151 for(int i=3 ; i<maxn ;i++)
    152   if(mtmp[i]==4){
    153     printf("%d %d %d %d ",i,i,i,i);
    154     mtmp[i]-=4;
    155     output();
    156     return ;
    157   }
    158 
    159  if(mtmp[16]==1&&mtmp[17]==1){
    160      printf("%d %d ",16,17);
    161      mtmp[16]=mtmp[17]=0;
    162      output();
    163      return ;
    164  }
    165    puts("没有牌能压过!");
    166    return ;
    167 }
    168 
    169 
    170 //如果是连对处理方案
    171 void AlgLDOrShZi(int var){
    172 
    173   int i=mn+1 ,len = mx-mn+1 ,kk=0;
    174   struct LianD   Ld , Tmpld;
    175 
    176        Ld.init();
    177     //时间复杂度为0(n^2)
    178  for( i = mn+1 ; i<15 ; i++){
    179         Tmpld.init();
    180         Tmpld.tem=i;
    181     for(int j=i ; j<i+len ; j++){
    182      if(mtmp[j]>=var){
    183 
    184         if(mtmp[j]==var){
    185             Tmpld.du++;
    186         }
    187          Tmpld.cnt++;
    188      }else{
    189           Tmpld.init();
    190           Tmpld.tem=j+1;
    191       }
    192      if(Tmpld.cnt==len){
    193          Tmpld.en =Tmpld.tem;
    194          if(Ld.en==0||Ld.du<Tmpld.du)
    195             Tmpld.copfun(&Ld);
    196              break;
    197      }
    198     }
    199  }
    200   if(Ld.cnt == len){
    201       puts("提示:");
    202     for(i=Ld.en; i<Ld.en+len ;i++){
    203           mtmp[i]-=var;
    204           kk=0;
    205     while(kk++<var)
    206         printf("%d " ,i);
    207     }
    208      output();
    209   }else{
    210     //寻求炸弹或者王炸
    211     ZhaDan();
    212   }
    213 
    214 }
    215 
    216 //三带的处理情况
    217 
    218 void  AlgShanDai(){
    219 
    220   int pos=0 , cnt=0 , res=0,fcnt=0;
    221   int mcnt=0 , mpos=0 ;
    222   //分析牌型
    223   for(int i=mn;i<=mx ;i++){
    224     if(rtmp[i]==3){
    225         pos=i;
    226         cnt++;
    227      }else if(rtmp[i]>0){
    228           res+=rtmp[i];  //统计剩余牌的数量
    229           fcnt++;
    230      }
    231     }
    232     if((fcnt==cnt&&res%cnt==0)||(fcnt<cnt&&(fcnt*res==cnt||0==res))) ;
    233     else{
    234       puts("输出的牌不符合规则!请重新输出:");
    235       return ;
    236     }
    237      res/=cnt;
    238      for(int i=pos-cnt+2 ; i<=pos; i++){
    239             if(rtmp[i]!=3){
    240             puts("输出的牌不符合规则!请重新输出:");
    241              return ;
    242             }
    243      }
    244 
    245   //如果为三带情况 即 cnt =1
    246     for(int i=pos-cnt+2 ; i<17 ;i++){
    247        if(mtmp[i]==3){
    248             mpos=i;
    249             mcnt++;
    250        }else
    251             mcnt=0;
    252        if(mcnt==cnt) break;
    253     }
    254     //查询副牌是否能够满足
    255     if(mcnt==cnt){
    256       //说明有解决方案
    257       int stpos = mpos - cnt +1 ;
    258       int src[maxn]={0} ,tt=0;
    259       bool tag = false;
    260       for(int i=3 ; i<17 ;i++){
    261         //满足不再连续范围之内的即可333444不能为3,4
    262         if(i<stpos||i>mpos){
    263           if(mtmp[i]>=res){
    264              for(int kk=0 ; kk<mtmp[i] ;kk+=res){
    265                   src[tt++]=i;
    266                   if(tt==cnt){
    267                     tag = true;
    268                     break;
    269                   }
    270              }
    271           }
    272         }
    273         if(tag)  break ;
    274       }
    275       if(tt==cnt){
    276         //则解决方案为
    277         int mstpos = mpos - cnt +1;
    278         for(int i=mstpos ; i<=mpos ; i++){
    279              printf("%d %d %d " ,i,i,i);
    280              mtmp[i]-=3;
    281         }
    282         //打印副牌
    283         for(int i=0; i<tt ;i++){
    284           for(int k=0 ;k<res ;k++){
    285               printf("%d ",src[i]);
    286           }
    287             mtmp[src[i]]-=res;
    288          }
    289            output();   //打印剩余牌
    290       }
    291     }else{
    292 
    293       //查询是否有炸弹
    294       ZhaDan();
    295     }
    296 }
    297 
    298 //四带情况
    299 void AlgSiDai(){
    300     if(chu[0]>4)  ZhaDan();
    301     else{
    302        for(int i=chu[1]+1 ; i<15 ; i++){
    303           if(mtmp[i]==4){
    304                 printf("%d %d %d %d ",i,i,i,i);
    305                 mtmp[i]-=4;
    306                 output();
    307               return ;
    308         }
    309     }
    310    if(mtmp[16]==1&&mtmp[17]==1){
    311      printf("%d %d ",16,17);
    312       mtmp[16]=mtmp[17]=0;
    313       output();
    314       return ;
    315 
    316 
    317 
    318 
    319 
    320  }
    321    puts("没有牌能压过!");
    322    return ;
    323   }
    324 }
    325 
    326 
    327 //对子的情况
    328 void AlgDuiZi(){
    329     for(int i=chu[1]+1 ; i<16 ;i++)
    330     {
    331         if(mtmp[i]>1&&mtmp[i]<4){
    332             printf("%d %d 
    ",i,i);
    333             mtmp[i]-=2;
    334             output();
    335             return ;
    336         }
    337     }
    338     ZhaDan();
    339 }
    340 
    341 //对于个子的情况
    342 void AlgGreZi(){
    343 
    344 for(int i=chu[1]+1 ; i<18 ;i++)
    345     {
    346         if(mtmp[i]>0&&mtmp[i]<4){
    347             printf("%d 
    ",i);
    348             mtmp[i]-=1;
    349             output();
    350             return ;
    351         }
    352     }
    353     ZhaDan();
    354 }
    355 
    356 //查询对应的方案
    357 
    358 //对子
    359 
    360 bool IsDuiZi(){
    361 
    362   if(chu[0]==2)  //则必定是对子
    363      return true;
    364  return false ;
    365 }
    366 
    367 //个子
    368 bool IsGreZi(){
    369 
    370  if(chu[0]==1)  //则必定是对子
    371      return true;
    372 
    373  return false ;
    374 }
    375 
    376 //判断是否是顺子
    377 bool IsShunZi(){
    378 
    379 //顺子的条件
    380 if(chu[0]>4){
    381 if((mx-mn+1==chu[0])&& mx<15)
    382     return true ;
    383 }
    384 return false;
    385 }
    386 
    387 //判断是否是连对
    388 bool IsLianDui(){
    389  if(chu[0]>5&&mx<15){
    390     for(int i=mn; i<=mx ;i++)
    391          if(rtmp[i]!=LianDui)
    392             return false;
    393    return true ;
    394  }
    395   return false;
    396 }
    397 
    398 //判断是否是三带
    399 bool IsShanDai(){
    400 
    401       for(int i=mn; i<=mx ;i++)
    402          if(rtmp[i]==3)
    403             return true;
    404 
    405   return false ;
    406 }
    407 
    408 
    409 
    410 //判断是否是四带或者炸弹
    411 bool IsSiDai(){
    412 
    413    for(int i=mn; i<=mx ;i++)
    414     if(rtmp[i]==4)
    415         return true;
    416 
    417     return false ;
    418 }
    419 
    420 
    421 //统计判断
    422 void AlgMxn(){
    423 
    424       //求最大值,最小值
    425   for(int i =3 ; i<= 17 ; i++)
    426       if(rtmp[i]>0){
    427           mn = i;
    428           break;
    429     }
    430    for(int i =17 ; i>= 3 ; i--)
    431       if(rtmp[i]>0){
    432           mx = i;
    433           break;
    434       }
    435 
    436 }
    437 
    438 void print(){
    439 
    440  int i;
    441  for(i=1; i<17; i++)
    442     printf("%d ", mycod[i]);
    443  printf("%d
    ", mycod[17]);
    444 
    445 }
    446 
    447 //检测出牌方
    448 bool checked(){
    449 
    450   for(int i=1 ; i<maxn ;i++){
    451      if(cod[i]<rtmp[i])
    452         return false;
    453   }
    454 
    455    if(IsGreZi()
    456       ||IsDuiZi()
    457       ||IsShunZi()
    458       ||IsSiDai()
    459       ||IsShanDai()){
    460         for(int i=1; i<=chu[0] ;i++){
    461             cod[chu[i]]--;
    462         }
    463       }
    464       return true ;
    465     //如果为一对王
    466     if(chu[0]==2&&mtmp[16]==1&&mtmp[17]==1)
    467         return true;
    468   return false;
    469 }
    470 
    471 int main(int argc , char * argv)
    472 {
    473 
    474  init();
    475 
    476  memset(mtmp , 0 , sizeof(mtmp));
    477 
    478  connt(mtmp , mycod);
    479  print();
    480 
    481  while(true){
    482    printf("请出牌:
    ");
    483   while(1){
    484   inputs();
    485   memset(rtmp , 0 ,sizeof(rtmp));
    486   connt(rtmp , chu);
    487   AlgMxn();
    488   if(checked())   break;
    489   else
    490      puts("输出的牌不符合规则!请重新输出:");
    491   }
    492         //如果满足顺子
    493     if(IsGreZi())
    494           AlgGreZi();
    495     else
    496         if(IsDuiZi())
    497              AlgDuiZi();
    498     else
    499         if(IsShunZi())
    500              AlgLDOrShZi(ShunZi);
    501     else
    502         if(IsLianDui())
    503              AlgLDOrShZi(LianDui);   //对于连对的情况
    504     else
    505         if(IsShanDai())
    506              AlgShanDai();
    507     else
    508         if(IsSiDai())
    509              AlgSiDai();
    510 
    511    if(mtmp[0]<1){
    512       puts("恭喜你,win!");
    513     break;
    514    };
    515  }
    516  return 0;
    517 
    518 }

     

  • 相关阅读:
    CS Academy Round #65 Count Arrays (DP)
    Codeforces Gym 101194C Mr. Panda and Strips(2016 EC-Final,区间DP预处理 + 枚举剪枝)
    Codeforces 915F Imbalance Value of a Tree(并查集)
    HDU 4866 Shooting (主席树)
    玲珑杯 Round #5 Problem E Tetration (枚举 + 欧拉公式)
    Codeforces 906D Power Tower(欧拉函数 + 欧拉公式)
    第十三届北航程序设计竞赛决赛网络同步赛 B题 校赛签到(建树 + 打标记)
    TopCoder SRM 722 Div1 Problem 600 DominoTiling(简单插头DP)
    Codeforces 901C Bipartite Segments(Tarjan + 二分)
    supervisor安装与使用
  • 原文地址:https://www.cnblogs.com/gongxijun/p/4689249.html
Copyright © 2020-2023  润新知