首页 > 其他分享 >UVA11210 题解

UVA11210 题解

时间:2023-09-10 13:55:56浏览次数:36  
标签:UVA11210 刻子 return ++ 题解 34 int true

思路分析

一道模拟。

一共只有 \(34\) 种牌,因此可以一次判断是否“听”这些牌。比如,为了判断是否“听”一万,只需要判断自己拿到这张一万后能否可以继续和牌。这样,问题就转化成了给定 \(14\) 张牌,判断是否可以和牌。为此,我们可以递归求解:首先将两张牌作为“将”,然后每次选 \(3\) 张作为刻子或者顺子。

选将有 \(5\) 种方法(一万、二万、三万、四万、五万都可以做将)。如果选五万做将,一万要么属于一个刻子,要么属于一个顺子。注意,这是不必考虑其他拍是如何形成刻子或者顺子的,否则会出现重复枚举。

为了快速选出将、刻子和顺子,我们用一个 \(34\) 维向量来表示状态,即每种牌所剩余的张数。除了第一次直接枚举将牌之外,每次只需要就考虑编号最小的牌,看它是否形成刻子或者顺子,并且递归判断。但是本题有个陷阱,每一种牌只有 \(4\) 张,所以 1S1S1S1S 是不“听”任何牌的。

程序实现

#include <bits/stdc++.h>
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 kase, c[34], mj[15];
bool ok;
char s[100];
int convert(char *s) { // 预处理
	for (int i = 0; i < 34; i++)
		if (!strcmp(mahjong[i], s))
			return i;
	return -1;
}
bool search(int dep) { // 回溯法递归
	for (int 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 (int 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;
}
bool check() {
	for (int i = 0; i < 34; i++)
		if (c[i] >= 2) { // 将牌
			c[i] -= 2;
			if (search(0)) return true;
			c[i] += 2;
		}
	return false;
}
int main() {
	while (scanf("%s", s) == 1) {
		if (s[0] == '0') break;
		printf("Case %d:", ++kase);
		mj[0] = convert(s);
		for (int i = 1; i < 13; i++) {
			scanf("%s", s);
			mj[i] = convert(s);
		}
		ok = false;
		for (int i = 0; i < 34; i++) {
			memset(c, 0, sizeof(c));
			for (int j = 0; j < 13; j++) c[mj[j]]++;
			if (c[i] >= 4) continue; // 每张牌最多只有4张
			c[i]++; // 假设拥有这张牌
			if (check()) { // 如果“和”了
				ok = true; // 那么听这张牌
				printf(" %s", mahjong[i]);
			}
			c[i]--;
		}
		if (!ok) printf(" Not ready");
		puts("");
	}
	return 0;
}

标签:UVA11210,刻子,return,++,题解,34,int,true
From: https://www.cnblogs.com/IShallReturn/p/UVA11210-ti-jie.html

相关文章

  • UVA1352 题解
    思路分析构造排列表立方体只有\(4\)个,暴力法是可行的。但是如果我们要暴力,首先得清楚一个立方体到底有几种不同的旋转方式。接下来,我们用“姿态”一词代替“旋转方法”。假设\(6\)个面的编号为\(1\sim6\),从中选择一个面作为“顶面”,“顶面”的对面为“底面”。然后我们在......
  • UVA11464 题解
    思路分析暴力枚举?我们可以枚举每个数字变或不变,最后判断整个矩阵是否满足条件。但是,这样做最多需要枚举\(2^{255}≈5\times10^{67}\)中情况,是一定会超时的。大眼观察注意到\(n\le15\),第一行只有不超过\(2^{15}=32768\)种可能,所以第一行的情况是可以枚举的。接下来,根据第......
  • 题解 SP4586 Texas Trip
    首先题目翻译是有问题的,求的不是矩形而是最小的正方形。Solution先考虑一下若正方形的边都只能平行于坐标轴怎么做:找到\(x,y\)方向的坐标最值,那么答案就是\(\max^2\{X_{\max}-X_{\min},Y_{\max}-Y_{\min}\}\)。接下来,若正方形可以是斜着的,我们只需把坐标轴旋转,然后同样找出......
  • 题解 P8389【[COI2021] Izvanzemaljci】
    (本题解的所有图片使用GeometryWidget进行绘制)(一)\(K=1\)情况\(K=1\)是平凡的。(二)\(K=2\)情况显然,对于平面内的两个不交正方形,存在至少一条平行于坐标轴的直线将它们划分到两侧。以直线平行于\(y\)轴为例。考虑按\(x\)轴正方向扫描线。先将点按照\(x\)坐标排序,维......
  • cnpm : 无法加载文件 \npm\cnpm.ps1,因为在此系统上禁止运行脚本。 问题解决
    很久没有弄前端VUE了。最近用到的vscode进行前端摸索。在用NPM的时候,发现有点慢,于是切换到了cnpm。在使用cnpm进行运行的时候报错了。“cnpm:无法加载文件C:\Users\Administrator\AppData\Roaming\npm\cnpm.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅https:/go.mi......
  • 【题解】三连击
    [NOIP1998普及组]三连击思路想一想桶得到三个数之后把每一位依次存入桶然后遍历这个桶,看哪一位为\(0\)代码//语言:C++#include<iostream>#include<cstring>//memsetusingnamespacestd;intmain(){ for(inti=123;i<=987/3;i++) { inta=i,b=2*i,c=3*i; i......
  • P3533 [POI2012] RAN-Rendezvous 题解
    P3533[POI2012]RAN-Rendezvous题目大意:给定外向树森林,每次给定两个起始点,求两个点沿边移动最少步数相遇。\(n\)个点,\(n\)条边,并且每个点有唯一的出边,显然构成了多棵基环树,对于每个基环树分别处理:找出环上的点,因为要求支持求出任意两点距离,前缀和一下即可。对于询问,如果在两......
  • vncviewer黑屏问题解决
    如果不知道kill多少值,可通过ps-ef|grepvnc进行查看1.先kill掉现在的vnc端口进程(假设端口是1):比如:vncserver-kill:12.打开启动文件xstartup:vim~/.vnc/xstartup3.修改其中的内容如下:#!/bin/shexportXKL_XMODMAP_DISABLE=1unsetSESSION_MANAGERunsetDBUS_SESSION_BUS_AD......
  • CF1570D 题解
    思路分析前言题解区好似没有用哈希的啊。发现大家都在用map来存是否出现过数字,但是需要注意的是,map的单次查询时间复杂度是\(\mathcalO(\logn)\)的,对于大规模的数据就很可能会TLE。所以,我们可以使用哈希的方法来判断数字是否出现过。浅谈哈希哈希,是通过哈希函数将数......
  • 【题解】Educational Codeforces Round 143(CF1795)
    A.TwoTowers题目描述:有\(a,b\)两座由红蓝色方块垒成的塔,其中\(a\)的高度为\(n\);\(b\)的高度为\(m\),用R代表红色;用B代表蓝色。你可以多次把其中一座顶端的方块移到另一座的顶端(可以不移动)。问有没有一种方法可以使两座塔中均没有连续的同颜色方块。题目分析:可以......