《算法竞赛-训练指南》第一章-1.9——UVa11210

来源:互联网 发布:windows文件监控 编辑:程序博客网 时间:2024/05/24 04:07

这是个中国麻将的问题,也是道比较麻烦的模拟题目,自己如果没有看题解,私自认为还是写不出来的。

因为思想都没有,解决问题的办法也没有。根本就是一片空白,但看了题解,才豁然开朗,原来是这么回事!


其中,很重要的一点就是,将你所需要的题目中给出的事例打成表,然后转换成唯一的数字问题,这样找起来,对应起来就简单多了。

然后就是枚举,说实话,天天看别人枚举,枚举。以为是一种很简单的方法,但其实,枚举是一种很奇怪的思想,是一种计算机独有的思想,你要学会用计算机思考问题,而不是用人的智能化去想问题,那么你永远都做不会枚举的题目。

此题的步骤。找听牌,不如就给他所有种类的牌,然后判断这种状态是不是赢的状态。当然赢的状态很多种,但我们只要能找到一种,那么这张牌就是一张听牌。

要赢,就必须要有唯一的一对将,所以我们首先就要把将的问题解决,如果连将都没有,那肯定是赢不了的。

然后就是一个一个的去三个和顺子。当然这两个是互不影响的。而且在每次去的过程中,都要回溯递归求解。即不成功就恢复原来的数据。

好吧,这样做起来就基本上能作对了,但是,如果不小心,想的不周到,,这道题目还是很难A的。

贴出代码:

#include <stdio.h>#include <string.h>#include <iostream>#include <string>#include <algorithm>using namespace std;char mahjong[44][22] = {"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"};int mj[22];int c[44];int converse(char *s) //将输入的字符串对应到每一种牌的id上 {for (int i = 0; i < 34; i++){if (strcmp(mahjong[i], s) == 0){return i;}}return -1;}bool search(int dep){for (int i = 0; i < 34; i++){if (c[i] >= 3)//找到三个. {if (dep == 3) //如果前面的已经满足了三个,那么这个一满足,就可以直接返回true {return true;}c[i] -= 3;if (search(dep + 1))//如果不满足,就继续递归调用 {return true;}c[i] += 3;}}for (int i = 0; i <= 24; i++) //开始的时候把找三个的和找顺子的在一起了,明天不可以.找三个是找三个,找顺子是找顺子, {//两者丝毫不一样. if (i % 9 <= 6 && c[i] >= 1 && c[i + 1] >= 1 && c[i + 2] >= 1) // 注意i%9的含义是找到对应一起的顺子然后小于6是为了满足对应一起. {if (dep == 3){return true;}c[i] -= 1;c[i + 1] -= 1;c[i + 2] -= 1;if (search(dep + 1)){return true;}c[i] += 1;c[i + 1] += 1;c[i + 2] += 1;}}return false;}bool check(){for (int i = 0; i < 34; i++){if (c[i] >= 2){//这里是不应该处理4个的时候的,四个仍然可以拿两个来当将的;错死我了. c[i] -= 2;if (search(0)){return true;}c[i] += 2;}}return false;}int main(){char s[100];int cnt = 1;while (scanf("%s", s) != EOF){if (s[0] == '0')//处理输入结束 {break;}mj[0] = converse(s);for (int i = 1; i <= 12; i++){scanf("%s", s);mj[i] = converse(s);}printf("Case %d:", cnt++);int flag = 0;for (int i = 0; i < 34; i++){memset(c, 0, sizeof(c)); // 因为每次的处理都把C给弄坏了,所以每一次单独求一下c for (int j = 0; j < 13; j++){c[mj[j]]++;}if (c[i] >= 4){continue;}c[i]++;if (check()){printf(" %s", mahjong[i]);//这个处理最后输出结果的方法也不错,因为case 后面又个空格,所以一切的输出都可以这样了. flag = 1;//自己不用去可以控制格式了. }c[i]--;}if (flag == 0){printf(" Not ready");}printf("\n");}//system("pause");return 0;}


原创粉丝点击