您的位置:首页 > 其它

uva 11210 - Chinese Mahjong(暴力搜索)

2016-12-05 15:04 375 查看
        这道题目是《算法竞赛入门经典训练指南》第1章算法设计基础的例9,看起来有点麻烦,最近开始学打麻将,比较好的理解了这道题的意思,之前一直都不能理解题意。

        有了一定的麻将胡牌基础,这道题很容易理解。胡牌规则很简单,一个将(两个一样),3个顺子(3个同花相连的牌)或刻子(3张相同的牌)即可胡牌。题目的要求是给13 张牌判断是否已经听牌,即再有一张某种花色牌即可胡牌。如果是,输出需要哪一种花色牌即可胡牌,如果不是输出not ready。

        算法的大致思路,首先枚举34种花色牌,表示有这种花色的牌可以胡牌(如果这种花色牌在13张中已经有4张,则跳过)。现在即有14张牌,对于这14张牌,再枚举34张种花色牌,表示有这种花色的两张牌则作为将,再对剩下12张牌进行操作。

        剩下的12张牌使用dfs,及当搜索4次时,若果都符合则可以听牌。剩下的12张牌,依旧是枚举34种花色牌,先找这种花色是否有至少3张牌,如果有,则构成顺子,再继续搜索。如果没有则判断这张牌和与它后面相连的2张牌能否构成刻子,若可以,则构成刻子,再继续搜索。如果不能,则表示没有听牌,则跳出dfs,继续枚举将牌。需要注意的是Dong,Nan,Xi,Bei,Zhong,Fa,Bai都不能构成刻子。

        存储方式则是先用一个二维字符数组存下所有的麻将花色,再用一维数组通过预处理13张牌保存下13张各种花色的牌各有多少张。

        注意:《算法竞赛入门经典训练指南》上给的程序个人感觉有点小问题。在枚举将牌和搜索顺子、刻子的两个函数里,每当成功找到时直接返回true但是并没有将之前减掉的牌数加回,这样容易造成只能找到一个能够听牌的花色,剩下的花色找不出来,所以在每个return true之前都需要添加上牌数加回的代码。

#include <iostream>
#include "stdio.h"
#include "string.h"
using namespace std;
int n[35];
char mj[35][6] = {"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 convert(char a[])
{
int i;
for(i = 0; i < 34; i++)
if(!strcmp(mj[i], a))
n[i]++;
}
bool sear(int tmp, int j, int k)
{
int i;
for(i = 0; i < 34; i++)
{
if(n[i] == 3)
{
if(tmp == 3)
return true;
n[i] -= 3;
if(sear(tmp + 1, j, k))
{
n[i] += 3;
return true;
}
else
n[i] += 3;
}
if(i < 27 && i % 9 < 7 && n[i] > 0 && n[i + 1] > 0 && n[i + 2] > 0)
{
if(tmp == 3)
return true;
n[i]--;
n[i + 1]--;
n[i + 2]--;
if(sear(tmp + 1, j, k))
{
n[i]++;
n[i + 1]++;
n[i + 2]++;
return true;
}
else
{
n[i]++;
n[i + 1]++;
n[i + 2]++;
}
}
if(n[i] > 0)
return false;
}
return false;
}
bool jiang(int tmp)
{
int i;
for(i = 0; i < 34; i++)
{
if(n[i] > 1)
{
n[i] -= 2;
if(sear(0, tmp, i))
{
n[i] += 2;
return true;
}
else
n[i] += 2;
}
}
return false;
}
int main()
{
int i, f, cas = 0;
char a[6];
while(~scanf("%s", a))
{
if(a[0] == '0')
break;
memset(n, 0, sizeof(n));
convert(a);
for(i = 1; i < 13; i++)
{
scanf("%s", a);
convert(a);
}
f = 1;
printf("Case %d:", ++cas);
for(i = 0; i < 34; i++)
{
if(n[i] == 4)
continue;
n[i]++;
if(jiang(i))
{
printf(" %s", mj[i]);
f = 0;
}
n[i]--;
}
if(f)
printf(" Not ready");
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息