Uva-11210-Chinese Mahjong

本文介绍了一种使用回溯法实现的麻将听牌算法。通过枚举所有可能的情况,利用递归深度搜索来判断是否能胡牌。文章详细解释了算法的实现细节,并列举了常见的错误及解决方案。

初看题目觉得有点恶心,看了书上分析后以自己的理解写了一遍。

思路是回溯法枚举所有情况。

用cnt[i]表示第i张牌有cnt[i]张。

首先将i从0到33枚举听牌,然后j从0到33枚举将牌,相应的cnt数组做修改(但是注意每次改变后到下一种情况前需要将cnt恢复回原来的样子),对use也做修改(use在下面有解释),接着调用dfs(0)。


下面解释dfs(i):

这里的i和书上的不同,书上的i是表示当前组第i个3张牌,所以只要在组第3个3张牌时成功就表示胡了。我的i是指牌的id,即第i张牌。那么,我是怎么判断胡了呢?为此我用变量use表示当前已用手牌数,故当use==14时即可判断牌胡了。


当cnt[i]不等于0时,就要将i牌用完,以i来尝试组成“碰”或者“顺子”,相应更改cnt,use。

注意下一层递归时不是dfs(i+1)而是dfs(i),因为不知道i牌是否用完。


当cnt[i]等于0时,说明i牌没有了,故调用dfs(i+1)。



这题我WA的原因分别是:1.把DONG,NAN,XI等也当做顺子了;

  2.听牌重复输出。

其实我一开始也有注意听牌不能重复输出的,但是以为我的代码已经规避了这个问题,所以没考虑,最后还是用别人的测试数据才找出来的,我想可能是我开始时并不知道什么地方会造成重复输出。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const char* mahjong[] = {"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 cnt[35]; //cnt[x] = y 表示第x张牌有y个 
int use; // use表示(通过将,砰,顺子)用掉的牌数,用来判断是否胡了,use == 14表示胡了 
bool ok; // 判断是否存在听牌 

int id(char* msg){
  for(int i = 0; i < 34; i++){
	  if(strcmp(msg,mahjong[i]) == 0) return i;				
  }		
}

//判断是否在“1S ~ 7S” , “1T ~ 7T”, “1W ~ 7W”范围内 
bool chow(int i){
  if(0 <= i && i <= 6) return true;
	if(9 <= i && i <= 15) return true;
	if(18 <= i && i <= 24) return true;
	return false;		 
}
 
bool dfs(int i){  
  if(use == 14) {ok = true; return true;}
  if(i >= 34) return false;  
  if(cnt[i] == 0) return dfs(i+1);
  bool ok2 = false;
  
  if(cnt[i] >= 3){		
	  cnt[i] -= 3;
	  use += 3;
		if(dfs(i))ok2 = true;
		use -= 3;
		cnt[i] += 3;					
  }
  
  if(!ok2 && chow(i) && cnt[i] && cnt[i+1] && cnt[i+2]){
	  cnt[i]--; cnt[i+1]--; cnt[i+2]--;
		use += 3;
		if(dfs(i))ok2 = true;
		use -= 3;
		cnt[i]++; cnt[i+1]++; cnt[i+2]++;	 
  }
  
  return ok2;
}



int main(){		
	char msg[10];
	int kase = 0;
	while(scanf("%s",msg) && strcmp(msg,"0")){
    printf("Case %d: ",++kase);
	  memset(cnt,0,sizeof(cnt));
		ok = false;
		cnt[id(msg)]++;
		for(int i = 0; i < 12; i++){
			scanf("%s",msg);
			cnt[id(msg)]++;		
		}
		
		bool fir = true;
		
		for(int i = 0; i < 34; i++){
		  if(cnt[i] == 4) continue;
			cnt[i]++;
			for(int j = 0; j < 34; j++){
				use = 0;			
				bool ok3 = false;
			  if(cnt[j] >= 2){			
				  cnt[j] -= 2;
				  use += 2;
					if(dfs(0)){									 
					  if(!fir) printf(" ");
						printf("%s",mahjong[i]);
						fir = false; 
						ok3 = true; 					 
				  }
					cnt[j] += 2;					
			  }		
				if(ok3) break; // 防止出现相同输出!!! 
			}
			cnt[i]--;				
	  }
		
		if(ok) printf("\n"); 
		else printf("Not ready\n");											
	}	
  return 0;		
}


### Mahjong Helper 麻将辅助工具及相关项目 Mahjong Helper 是一个开源项目,专注于为麻将玩家提供帮助和分析功能。其生态系统中包含多个相关项目,这些项目可以进一步扩展其功能并提升用户体验[^1]。 #### 1. Mahjong AI Mahjong AI 是基于 Mahjong Helper 开发的一个智能系统,主要用于自动分析玩家的手牌并提供决策建议。该工具通过复杂的算法模拟对手的行为,并预测可能的出牌策略,从而帮助用户在游戏中做出更明智的选择[^1]。 #### 2. Mahjong Scoreboard Mahjong Scoreboard 是一个记录和展示比赛得分的工具,能够与 Mahjong Helper 无缝配合使用。它支持多种计分规则,并允许用户自定义比赛设置。通过实时更新比分信息,Mahjong Scoreboard 可以让玩家更加专注于游戏本身,而无需担心繁琐的分数计算问题[^1]。 #### 3. Mahjong Rules Mahjong Rules 是一个详细记录各种麻将规则的仓库,旨在为 Mahjong Helper 提供全面的规则支持。无论是传统中国麻将还是日式立直麻将,该项目都涵盖了丰富的规则说明和示例代码,确保用户能够在不同规则下正确使用 Mahjong Helper[^1]。 #### 4. Mahjong Helper - Majsoul 助手 对于《雀魂Majsoul》的爱好者而言,Mahjong Helper - Majsoul 助手是一个不可或缺的工具。它不仅可以帮助初学者快速掌握游戏技巧,还能为高级玩家提供深入的数据分析和策略优化建议。这款工具极大地提升了用户的竞技乐趣和游戏体验[^2]。 #### 5. Akagi 项目 Akagi 是另一个与麻将相关的项目,主要功能是通过拦截和解析《雀魂Majsoul》的游戏数据来实现自动化操作。在 `settings.json` 文件中,用户可以配置多个参数,例如是否启用自动播放(Autoplay)、是否使用 mahjong-helper(Helper)、以及是否自动和牌(Autohu)。此外,Akagi 还支持 MITM 端口重定向和 XMLRPC 端口绑定等功能,为开发者提供了更大的灵活性[^3]。 ```python # 示例:Akagi 的 settings.json 配置文件 { "Unlocker": true, "Autoplay": false, "Helper": true, "Autohu": true, "Port": 8080, "XMLRPC": 9090, "Playwright": { "viewport": { "width": 1920, "height": 1080 } } } ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值