您的位置:首页 > 其它

uva 11210 Chinese Mahjong 中国麻将 dfs回溯

2015-09-26 23:53 351 查看
题目:https://uva.onlinejudge.org/external/112/11210.pdf

详见注释:

注意这道题的搜索方式,我之前虽然与答案一样,先找出将,再dfs,但是写的远远比答案麻烦。

#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<climits>
#include<queue>
#include<vector>
#include<map>
#include<sstream>
#include<set>
#include<stack>
#include<cctype>
#include<utility>
#pragma comment(linker, "/STACK:102400000,102400000")
#define PI 3.1415926535897932384626
#define eps 1e-10
#define sqr(x) ((x)*(x))
#define FOR0(i,n)  for(int i=0 ;i<(n) ;i++)
#define FOR1(i,n)  for(int i=1 ;i<=(n) ;i++)
#define FORD(i,n)  for(int i=(n) ;i>=0 ;i--)
#define  lson   num<<1,le,mid
#define rson    num<<1|1,mid+1,ri
#define MID   int mid=(le+ri)>>1
#define zero(x)((x>0? x:-x)<1e-15)
#define mk    make_pair
#define _f     first
#define _s     second

using namespace std;
//const int INF=    ;
typedef long long ll;
//const ll inf =1000000000000000;//1e15;
//ifstream fin("input.txt");
//ofstream fout("output.txt");
//fin.close();
//fout.close();
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
const int INF =0x3f3f3f3f;
const int maxn= 50   ;
const int N=    34   ;
//const int maxm=    ;
//by yskysker123
map<string ,int >mp;
int cnt[maxn];
char s[15][8];
bool ok;
char name[50][8]=
{"",
"1T","2T","3T","4T","5T","6T","7T","8T","9T",
"1S","2S","3S","4S","5S","6S","7S","8S","9S",
"1W","2W","3W","4W","5W","6W","7W","8W","9W",
"DONG","NAN","XI","BEI",
"ZHONG","FA","BAI"
  };

void Getmap()
{
    mp["1T"]= 1  ;mp["2T"]= 2  ;mp["3T"]= 3  ;mp["4T"]=  4 ;mp["5T"]=  5 ;mp["6T"]= 6  ;
    mp["7T"]= 7  ;mp["8T"]=  8 ;mp["9T"]= 9  ;

    mp["1S"]= 10  ;mp["2S"]=  11 ;mp["3S"]=  12;mp["4S"]=  13 ;mp["5S"]=  14 ;mp["6S"]=  15 ;
    mp["7S"]= 16  ;mp["8S"]= 17  ;mp["9S"]=  18 ;

    mp["1W"]= 19  ;mp["2W"]=  20 ;mp["3W"]=  21;mp["4W"]=  22;mp["5W"]=  23;mp["6W"]=   24;
    mp["7W"]=   25  ;mp["8W"]=   26;mp["9W"]=  27;

    mp["DONG"]=28;mp["NAN"]=29;mp["XI"]=30;mp["BEI"]=31;
    mp["ZHONG"]=32;mp["FA"]=33;mp["BAI"]=34;
}

void cope(int i)
{
   int x=mp[ (string)s[i] ];
   cnt[x]++;
}

bool dfs(int step)   //统计每种牌的个数cnt[],再根据cnt[]来加加减减进行dfs,比我原来的 对手里的14张牌进行顺次考虑  要简单的多。
{

    if(step==5)  return true;

    //作顺子
    for(int i=1;i<=27-2;i++)
    {
        if(i%9  ==8|| i%9  ==0) continue;//错误写法  :if(i%9 +1 ==8|| i%9 +1 ==9) continue;
        if(!cnt[i] ||  !cnt[i+1] || !cnt[i+2])  continue;
        cnt[i]--;cnt[i+1]--;cnt[i+2]--;
        if(dfs(step+1))  return true;
        cnt[i]++;cnt[i+1]++;cnt[i+2]++;
    }
    //作刻子
    for(int i=1;i<=N;i++)
    {
        if(cnt[i]<3)  continue;
        cnt[i]-=3;
        if(dfs(step+1) )  return true;
        cnt[i]+=3;
    }

    return false;

}

bool check(int x)             //注意这道题的搜索方式,我之前虽然与答案一样,先找出将,再dfs,但是写的远远比答案麻烦。
{
    memset(cnt,0,sizeof cnt);  //每次检查一种麻将 都初始化,直接将保存在数组里的输入信息再一次读取就行了,省去(开多个数组来避免回溯一半就跳出)的麻烦
    for(int i=1;i<=13;i++)
    {
        cope(i);
    }
    if(cnt[x]==4)  return false; //最大坑点,如果某个麻将已有四种颜色,那么你是不可能摸到这种麻将的。
    cnt[x]++;

    //将子:
    for(int i=1;i<=N;i++)
    {
        if(cnt[i]<2)  continue;

            cnt[i]-=2;

            if(dfs(1))  return true;

            cnt[i]+=2;    //回溯----dfs精髓
    }
    return false;

}

void work()
{
    ok=0;
    for(int i=1;i<=34;i++)
    {
        if(check(i)) ok=1, printf(" %s",name[i]);
    }
    if(!ok)  printf(" Not ready");
    putchar('\n');
}

int main()
{
    int kase=0;
    mp.clear();
    Getmap();
  while(~scanf("%s",s[1])&&strcmp(s[1],"0")!=0)
  {
     for(int i=2;i<=13;i++)
     {
         scanf("%s",s[i]);
     }
     printf("Case %d:",++kase);
     work();

  }

    return 0;
}


中国麻将,有意思。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: