麻将开金算法java代_中国麻将(Chinese Mahjong, UVa 11210)【JAVA算法实现】

题目描述麻将是一个中国原创的4人玩的游戏。这个游戏有很多变种,但本题只考虑一种有136张牌的玩法。这136张牌所包含的内容如下。饼(筒)牌:每张牌包括一系列

题目描述

麻将是一个中国原创的4人玩的游戏。这个游戏有很多变种,但本题只考虑一种有136张牌的玩法。这136张牌所包含的内容如下。

饼(筒)牌:每张牌包括一系列点,每个点代表一个铜钱。本题中用1T、2T、3T、4T、5T、6T、7T、8T、9T表示。

索(条)牌:每张牌由一系列竹棍组成,每根棍代表一挂铜钱。本题中用1S、2S、3S、4S、5S、6S、7S、8S、9S表示。

万牌:每张牌代表一万枚铜钱,如图1-14所示。本题中用1W、2W、3W、4W、5W、6W、7W、8W、9W表示。

风牌:东、南、西、北风。本题中用DONG、NAN、XI、BEI表示。

箭牌:中、发、白。本题中用ZHONG、FA、BAI表示。

总共有9×3+4+3=34种牌,每种4张,一共有136张牌。

其实麻将中还有如图1-17所示的8张花牌,所以共有136 + 8 = 144张牌,但是本题中不予考虑。

中国麻将的规则十分复杂,,本题中只需考虑部分规则。在本题中,手牌(即每个人手里的牌)总是有13张。如果多了某张牌以后,整副牌可以拆成一个将(两张相同的牌)、0个或多个刻子(3张相同的牌)和0个或多个顺子(3张同花相连的牌。注意,风牌和箭牌不能形成顺子),我们就说这手牌“听”这张牌,即拿到那张牌以后就赢了,称为“和”(实战中还要考虑番数和特殊和法,在本题中可以忽略)。

输入格式

输入数据最多50组。每组数据由一行13张牌给出,输入保证给出的牌是合法的。输入结束标记为一行单个0。

输出

对于每组数据,输出所有“听”的牌,按照描述中的顺序列出(1T-9T,1S-9S,1W-9W,DONG,NAN,XI,BEI,ZHONG,FA,BAI)。每张牌最多被列出一次。如果没有“听”牌,输出Not ready。

样例输入

1S

1S

2T

2T

2T

3S

3S

3S

4T

4T

4T

5S

5S

样例输出

Case:1

1S

5S

import java.util.Arrays;

import java.util.Scanner;

public class Main {

private final static String[] 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" };

private static int[] c = new int[34];

// 只在预处理调用,因此速度无关紧要

// 麻将列序号

public static int convert(String s) {

for (int i = 0; i < 34; i++)

if (s.equals(mahjong[i]))

return i;

return -1;

}

// 回溯法递归过程

// 遍历判断顺子和刻子,每当判断成立,相应麻将牌c[i]减一,继续递归调用search(int dep),若和了,那么dep=3。

private static boolean search(int dep) {

int i;

// 判读刻子

for (i = 0; i < 34; i++)

if (c[i] >= 3) {

if (dep == 3)

return true;

c[i] -= 3;

if (search(dep + 1))

return true;

c[i] += 3;

}

// 判断顺子

for (i = 0; i <= 24; i++)

if (i % 9 <= 6 && c[i] >= 1 && c[i + 1] >= 1 && c[i + 2] >= 1) {

if (dep == 3)

return true;

c[i]--;

c[i + 1]--;

c[i + 2]--;

if (search(dep + 1))

return true;

c[i]++;

c[i + 1]++;

c[i + 2]++;

}

return false;

}

// 判断是否和了

// 暴力找出所有的将牌,再根据各个将牌找出刻子和顺子。

private static boolean check() {

int i;

for (i = 0; i < 34; i++) {

if (c[i] >= 2) {

c[i] -= 2;

if (search(0))

return true;

c[i] += 2;

}

}

return false;

}

public static void main(String[] args) {

int caseno = 0, i, j;

boolean ok;

String s;

int mj[] = new int[15];

Scanner cin = new Scanner(System.in);

while (cin.hasNext()) {

s = cin.nextLine();

if (s.charAt(0) == '0')

break;

System.out.print("Case:" + (++caseno));

mj[0] = convert(s);

for (i = 1; i < 13; i++) {

s = cin.nextLine();

mj[i] = convert(s);

// System.out.println(mahjong[mj[i]]);

}

ok = false;

for (i = 0; i < 34; i++) {

Arrays.fill(c, 0);// 清零

for (j = 0; j < 13; j++)

c[mj[j]]++;

if (c[i] >= 4)

continue;

c[i]++;//假设摸了这张牌

if (check()) {//和了

ok = true;

System.out.println(mahjong[i]);//那么这副牌听这个牌

}

c[i]--;

}

if (!ok)

System.out.println("not ready");

System.out.println("\n");

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值