算法竞赛入门经典训练指南打卡
题目链接:UVa 11210
思路
简单的暴力枚举题,我们可以分别尝试添加34张牌中的一张牌,凑成14张牌,查看是否可以和牌
如果可以和牌,则输出这张牌,如果所有牌加上去都不可以和牌则输出Not ready
判断和牌的方式:枚举+深搜+回溯
首先枚举将,然后深搜其他的牌是否满足可以组成四组(刻子和顺子),如果可以则说明可以和牌
具体细节看到代码注释
代码如下:
#include <iostream>
#include <vector>
#define ton(i , n) for(int i = 0 ; i < n ; ++ i)
using namespace std ;
const string mahjong[34] = {"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"}; //将牌转换成数字,方便存储牌的数量
bool victory(vector<int> number , int d){
ton(i , 34)
if(number[i] >= 3){ //可以做成刻子
if (d == 3) //组数已经达到3组,加上当前这组刻子刚好四组,可以和牌
return true ;
number[i] -= 3 ; //做一组刻子
if(victory(number , d + 1)) //上一行代码做成了一组刻子,组数+1,深搜
return true ;
number[i] += 3 ; //这组刻子组成了无法和牌,拿回来
}
ton(i , 24)
if (i % 9 <= 6 && number[i] >= 1 && number[i + 1] >= 1 && number[i + 2] >= 1){ //顺子开头只能是1~7,且这3张牌都有至少一个
if (d == 3) //同上。加上当前这组顺子组成4组。和了
return true ;
number[i] -- ;
number[i + 1] -- ;
number[i + 2] -- ; //同上,组成顺子
if(victory(number , d + 1)) //同上,深搜
return true ;
number[i] ++ ;
number[i + 1] ++ ;
number[i + 2] ++ ; //同上,拿回来
}
return false ;
}
bool check(vector<int> number){
ton(i , 34)
if(number[i] >= 2){
number[i] -= 2 ; //将当前牌做为将
if (victory(number , 0)) //查找剩下的牌是否可以组成四组(刻子或者顺子)
return true ; //如果可以说明可行
number[i] += 2 ; //不可以则将之前去掉的将拿回来
}
return false ; //如果都不行返回false
}
int convert(string temp){
ton(i , 34)
if(mahjong[i] == temp)
return i ; //找到该牌,返回id
return -1 ;
}
int main(){
int k = 1 ;
bool ans ;
string temp ;
while (cin >> temp && temp != "0"){ //如果第一个输入为0则说明输入结束
vector<int> number(34 , 0) ; //number用来记录每张牌的数量
ans = false ;
number[convert(temp)] ++ ; //convert找到该牌对应的id,这张牌的数量+1
ton(i , 12){
cin >> temp ;
number[convert(temp)] ++ ; //输入剩下的十二张牌
}
cout << "Case " << k ++ << ":" ;
ton(i , 34){
if(number[i] == 4)
continue ; //number[i]为4,说明这张牌不可能再出现了
number[i] ++ ; //加入一张牌,凑成14张进行判断
if(check(number)){ //判断加入该牌之后是否可以和牌
ans = true ;
cout << " " << mahjong[i] ; //可以和牌,输出当前听的牌
}
number[i] -- ;
}
if(!ans)
cout << " Not ready" ; //如果无法和牌,输出Not ready
cout << endl ;
}
return 0 ;
}