HDU 4431 Mahjong (麻将、神坑模拟题)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4431

题面:

Mahjong

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 4219    Accepted Submission(s): 842

Problem Description

Japanese Mahjong is a four-player game. The game needs four people to sit around a desk and play with a set of Mahjong tiles. A set of Mahjong tiles contains four copies of the tiles described next:

One to nine Man, which we use 1m to 9m to represent;

One to nine Sou, which we use 1s to 9s to represent;

One to nine Pin, which we use 1p to 9p to represent;

Character tiles, which are:Ton, Nan, Sei, Pei, Haku, Hatsu, Chun, which we use 1c to 7c to represent.

A winning state means a set of 14 tiles that normally contains a pair of same tiles (which we call "eyes") and four melds. A meld is formed by either three same tiles(1m, 1m, 1m or 2c, 2c, 2c for example) or three continuous non-character tiles(1m, 2m, 3m or
5s, 6s, 7s for example).

However, there are two special winning states that are different with the description above, which are:

"Chii Toitsu", which means 7 different pairs of tiles;

"Kokushi Muso", which means a set of tiles that contains all these tiles: 1m, 9m, 1p, 9p, 1s, 9s and all 7 character tiles. And the rest tile should also be one of the 13 tiles above.

And the game starts with four players receiving 13 tiles. In each round every player must draw one tile from the deck one by one. If he reaches a winning state with these 14 tiles, he can say "Tsu Mo" and win the game. Otherwise he should discard one of his
14 tiles. And if the tile he throws out can form a winning state with the 13 tiles of any other player, the player can say "Ron" and win the game.

Now the question is, given the 13 tiles you have, does there exist any tiles that can form a winning state with your tiles?

(Notes: Some of the pictures and descriptions above come from Wikipedia.)

Input

The input data begins with a integer T(1≤T≤20000). Next are T cases, each of which contains 13 tiles. The description of every tile is as above.

Output

For each cases, if there actually exists some tiles that can form a winning state with the 13 tiles given, print the number first and then print all those tiles in order as the description order of tiles above. Otherwise print a line
"Nooten"(without quotation marks).

Sample Input

2
1s 2s 3s 2c 2c 2c 2p 3p 5m 6m 7m 1p 1p
1p 1p 2p 3p 4s 5s 6s 7c 7c 3s 3s 2m 2m

Sample Output

2 1p 4p
Nooten

Source

2012 Asia Tianjin Regional Contest

解题:

wa了八次,只能说自己太水或者说太懒,都不自己编几组样例测试下。题意是比较复杂的,做法是枚举加34张牌,看是否可以胡。可以赢的情况是3种。

1.有1筒,9筒,1万,9万,1索,9索,东南西北中发白。其中一种为2张。(国士无双)

2.有7对不同的对子。

3.4对顺子或者小包子+1对将军

顺子是指1s,2s,3s,包子是指1p,1p,1p。(以上专业术语摘自别人博客)

坑点:

1.注意是不同的对子。

2.检查时若把数量变更了,记得还原。

3.枚举34张牌的时候,注意牌数不能超过4张,此处神坑,但也说明自己思维不够全面,没有考虑到保证状态的合法性。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int cnt[35],cal[35],res[35],tmp[35];
//判断当前组合是否能够通过方式三胡
bool check()
{
   int sign=0;
   for(int i=1;i<=34;i++)
	   tmp[i]=cal[i];
   //此处是能在当前组合就组合,否则在后面就无法成顺子了
   for(int i=1;i<=9;i++)
   {
	  while(tmp[i])
	  {
		  if(tmp[i]>=3)
		  {
			  tmp[i]-=3;
			  sign++;
		  }
		  else if(i<=7&&tmp[i+1]&&tmp[i+2])
		  {
			  tmp[i]--;
			  tmp[i+1]--;
			  tmp[i+2]--;
			  sign++;
		  }
		  else break;
	  }
   }
   for(int i=10;i<=18;i++)
   {
	   while(tmp[i])
	  {
		  if(tmp[i]>=3)
		  {
			  tmp[i]-=3;
			  sign++;
		  }
		  else if(i<=16&&tmp[i+1]&&tmp[i+2])
		  {
			  tmp[i]--;
			  tmp[i+1]--;
			  tmp[i+2]--;
			  sign++;
		  }
		  else break;
	  }
   }
   for(int i=19;i<=27;i++)
   {
	  while(tmp[i])
	  {
		  if(tmp[i]>=3)
		  {
			  tmp[i]-=3;
			  sign++;
		  }
		  else if(i<=25&&tmp[i+1]&&tmp[i+2])
		  {
			  tmp[i]--;
			  tmp[i+1]--;
			  tmp[i+2]--;
			  sign++;
		  }
		  else break;
	  }
   }
   for(int i=28;i<=34;i++)
   {
	   if(tmp[i]==3)
	   {
		   tmp[i]=0;
		   sign++;
	   }
   }
   //4对方合法
   if(sign==4)return true;
   else return false;
}
int main()
{
	int t,n,ans;
	char c;
	scanf("%d",&t);
	while(t--)
	{
		//编号m:1-9 s:10-18 p:19-27 c:28-34
		ans=0;
		memset(cnt,0,sizeof(cnt));
		memset(res,0,sizeof(res));
		for(int i=0;i<13;i++)
		{
			scanf("%d%c",&n,&c);
			if(c=='m')
				cnt[n]++;
			else if(c=='s')
				cnt[n+9]++;
			else if(c=='p')
				cnt[n+18]++;
			else
				cnt[n+27]++;
		}
		//拷贝
        for(int i=1;i<=34;i++)
		{
			for(int j=1;j<=34;j++)
				cal[j]=cnt[j];
			cal[i]++;
			//某张牌数大于4,不合法
			if(cal[i]>4)continue;
			//通过方式一胡
			bool flag=true;
			if(cal[1]&&cal[9]&&cal[10]&&cal[18]&&cal[19]&&cal[27])
			{
				cal[1]=cal[9]=cal[10]=cal[18]=cal[19]=cal[27]=0;
				for(int j=28;j<=34;j++)
				{
					if(cal[j]==0)
						flag=false;
					else
						cal[j]=0;
				}
				if(flag)
				{
					for(int k=1;k<=34;k++)
					{
						if(cal[k])
						{
							flag=false;
							break;
						}
					}
					if(flag)
					{
						ans++;
						res[i]=1;
						continue;
					}
				}
			}
			for(int j=1;j<=34;j++)
				cal[j]=cnt[j];
			cal[i]++;
			int x=0;
			//通过方式二胡
			for(int j=1;j<=34;j++)
			{
				if(cal[j]==2)
					x++;
			}
			if(x==7)
			{
				ans++;
				res[i]=1;
				continue;
			}
			//枚举方式三
			for(int j=1;j<=34;j++)
			{
				if(cal[j]>=2)
				{
					cal[j]-=2;
					if(check())
					{
						ans++;
						res[i]=1;
						cal[j]+=2;
						break;
					}
					cal[j]+=2;
				}
			}
		}
		if(ans)
		{
			printf("%d",ans);
			for(int i=1;i<=9;i++)
			{
				if(res[i])
					printf(" %dm",i);
			}
			for(int i=10;i<=18;i++)
			{
				if(res[i])
					printf(" %ds",i-9);
			}
			for(int i=19;i<=27;i++)
			{
				if(res[i])
					printf(" %dp",i-18);
			}
			for(int i=28;i<=34;i++)
			{
				if(res[i])
					printf(" %dc",i-27);
			}
			printf("\n");
		}
		else
			printf("Nooten\n");
	}
	return 0;
}

总结:

1.一些变量使用后,记得还原。代码长了,确实难发现,最好能精简代码。

2.自己生成的状态要确保合法,若不是看了别人的博客,怕是很难发现这个问题。

3.代码确定无误后,要从数据合法性出发去考虑。

4.还是那句话,不是样例过了,就行了,不如花上5分钟,把代码讲一遍给小鸭子听。(除非是特别短的代码,自己非常有把握的)

5.不要总是想着对的那个方向,要小心意外情况的发生。

6.逻辑需要推敲,不能想当然。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-07-30 03:20:24

HDU 4431 Mahjong (麻将、神坑模拟题)的相关文章

HDU 4925 Apple Tree(模拟题)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4925 解题报告:给你n*m的土地,现在对每一块土地有两种操作,最多只能在每块土地上进行两种操作,第一种是种苹果树操作,第二种是施肥操作,种苹果树操作可以使得该块地 长出一个苹果,施肥操作可以使得与这块土地相邻的土地的苹果产量变为原来的两倍,问可以得到的最多的苹果数量是多少? 例如一个4*4的土地,用1表示在该土地上做第一种操作,0表示在该土地上做第二种操作,可以得到最多苹果的操作如下: 0 1 0

hdu 4119 Isabella&#39;s Message 模拟题

Isabella's Message Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=4119 Description Isabella and Steve are very good friends, and they often write letters to each other. They exchange funny experiences, talk ab

HDU 1034 Candy Sharing Game 模拟题

一个分糖游戏,找了会规律,没找到,只能直接模拟玩了. 果然0ms过了,看来数据不大,只是考编码能力罢了. #include <stdio.h> #include <vector> #include <string.h> #include <algorithm> #include <iostream> #include <string> #include <limits.h> #include <stack> #

HDU - 4431 Mahjong

中华文化真是博大精深 这两天的Dark模拟题做的我要吐了 题目大意:给你13张麻将,求再加上哪张可以胡 胡的要求有三个 1.一个对子 +  4组 3个相同的牌或者顺子.  只有m.s.p是可以构成顺子的.东西南北这样的牌没有顺子. 2.7个不同的对子. 3.1m,9m,1p,9p,1s,9s,1c,2c,3c,4c,5c,6c,7c.  这13种牌每种都有,而且仅有这13种牌.肯定是有一种2张.其他的1张. 具体思路:枚举加那张牌,然后按题意模拟,判断是否胡了即可 我貌似wa了一页的样子,原因是

HDU 2414 Chessboard Dance(模拟题,仅此纪念我的堕落)

题目 模拟题也各种wa,我最近真的堕落了,,,,,智商越来越为负数了!!!!!!!! #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; char mp[10][10]; int d=-1;//0shang,1xia,2zuo,3you int x,y;//weizhi int weizhi(int i,int j) { if(mp[i][j]=='<'){x=

HDU 1337 The Drunk Jailer--(模拟题找规律)

题意:有n个监狱,共n轮,第 i 轮警察会去编号为 i 的倍数的监狱,如果是锁的就开锁,如果是开的就锁上,求n轮过后有多少犯人会逃出来 分析:这题实际上是个模拟题,因为数据很小我直接用两重循环模拟的,如果数据很大的话,就不能直接模拟了,模拟题卡时间多半是找规律. 这题的规律是:如果一个监狱被查看了偶数次的话相当于则什么都没发生,还是锁的,也就是说找没有锁上的监狱只要n以内找因数为奇数个的数有多少个即可 代码: #include<iostream> using namespace std; in

HDU 4431 Mahjong(神奇的麻将) 模拟

胡牌的情况 1.有1对相同的牌(对子),和4组meld(对不起我实在不知道怎么翻译了).meld就是3张相同的牌或者3张连续的牌(顺子).注意3张连续的c牌不能看做meld. 2.有7对不同的对子. 3.有1s,9s,1m,9m,1p,9p,和1c至7c这13种牌,并且其中有1种牌有2张. 做法是枚举1张牌加入牌组(第14张牌),然后判断当前牌组能不能胡. 对于第一种胡牌情况,先选出1对对子,在判断剩下的是不是4组meld. 对于第二.三种情况就直接判断了. 需要注意的是,每种牌最多只有4张,需

HDU - 4431 Mahjong (模拟+搜索+哈希+中途相遇)

题目链接 基本思路:最理想的方法是预处理处所有胡牌的状态的哈希值,然后对于每组输入,枚举每种新加入的牌,然后用哈希检验是否满足胡牌的条件.然而不幸的是,由于胡牌的状态数过多(4个眼+一对将),预处理的复杂度太高($O(34^5)$),因此需要想办法优化一下. 我们可以预处理出所有“加上一对将之后可以胡牌”的状态,这样预处理的复杂度就成了$O(34^4)$,在可接受的范围内了.在检验的时候,只需要枚举去掉哪一对将,就可以$O(1)$检验是否能胡牌了(有种中途相遇的感觉),另外两种特殊情况单独判断即

HDU 4431 Mahjong (DFS,暴力枚举,剪枝)

题意:给定 13 张麻将牌,问你是不是“听”牌,如果是输出“听”哪张. 析:这个题,很明显的暴力,就是在原来的基础上再放上一张牌,看看是不是能胡,想法很简单,也比较好实现,结果就是TLE,一直TLE,这不科学啊... 好不容易写出来的,竟然TLE...心痛.就是先确定一个将牌,然后再对刻子和顺子进行分析,其实是要剪枝的,就是在如果有1张或者两张牌,而你又不能构成刻子的时候,就要返回false,因为这就已经没解了. 这一个剪枝,就AC了. 代码如下: #pragma comment(linker,