JSOI2007 麻将 题解

时间: 1000ms / 空间: 131072KiB / Java类名: Main

描述

  麻将是中国传统的娱乐工具之一。麻将牌的牌可以分为字牌(共有东、南、西、北、中、发、白七种)和序数牌(分为条子、饼子、万子三种花色,每种花色各有一到九的九种牌),每种牌各四张。在麻将中,通常情况下一组和了的牌(即完成的牌)由十四张牌组成。十四张牌中的两张组成对子(即完全相同的两张牌),剩余的十二张组成三张一组的四组,每一组须为顺子(即同花色且序数相连的序数牌,例如条子的三、四、五)或者是刻子(即完全相同的三张牌)。一组听牌的牌是指一组十三张牌,且再加上某一张牌就可以组成和牌。那一张加上的牌可以称为等待牌。

  

在这里,我们考虑一种特殊的麻将。在这种特殊的麻将里,没有字牌,花色也只有一种。但是,序数不被限制在一到九的范围内,而是在1到n的范围内。同时,也没有每一种牌四张的限制。一组和了的牌由3m + 2张牌组成,其中两张组成对子,其余3m张组成三张一组的m组,每组须为顺子或刻子。现给出一组3m + 1张的牌,要求判断该组牌是否为听牌(即还差一张就可以和牌)。如果是的话,输出所有可能的等待牌。

输入格式

输入文件包含两行。

第一行包含两个由空格隔开整数n, m (9<=n<=400, 4<=m<=1000)。第二行包含3m + 1个由空格隔开整数,每个数均在范围1到n之内。这些数代表要求判断听牌的牌的序数。

输出格式

输出为一行。

如果该组牌为听牌,则输出所有的可能的等待牌的序数,数字之间用一个空格隔开。所有的序数必须按从小到大的顺序输出。如果该组牌不是听牌,则输出"NO"。

测试样例1

输入

9 4

1 1 2 2 3 3 5 5 5 7 8 8 8

输出

6 7 9

【解题思路】

一、枚举胡的牌,枚举哪个当一对,从左到右简单贪心扫描一遍即可,贪心是指可以取刻子的就取刻子,剩下的去顺子,O(n3)

二、枚举胡的牌,f[I,p,j,k]:i=0表示已找到了对子,i=1表示没找到,已计算了前p位,p+1等价于有j张牌,p+2等价于有k张牌的情况是否可能出现。 O(n2)

三、f[I,o,p,j,k]:o=0表示加了要胡的牌,o=1表示没加要胡的牌,i=0表示已找到了对子,i=1表示没找到,已计算了前p位,p+1等价于有j张牌,p+2等价于有k张牌的情况是否可能出现。 O(n)

【分析】

看到题我首先想到的是枚举,我们可以依次枚举每个数字,即要听的牌,看加上这个数字之后能不能和,能的话记录下来,不能的话继续枚举下一个数字。那问题就在于如何来判断加上枚举的牌能否和。

首先,在我们判断的时候,每个数字只有两种情况:

1、它是刻子(即它有三个)

2、它是顺子的一个(此处我们直接判断第一个即可)

然后在我们判断这种情况能否成立的时候,首先我们应该先枚举找将(也就是那个对子),找到将之后,去掉将(把这两个数的次数减掉),然后在这个将的情况下去从前往后枚举每一个数字,对每个数字进行判断是否满足上面两种情况。这样的话,第一种很简单(a[i]:=a[i] mod 3;),我们只需看第二种即可,满足的话减掉这三个数的次数,如果已经是倒数第二个数或者最后一个,后面已经不能有两个数了,但如果此时它仍然不为0的话证明肯定胡不了,所以退出,枚举下一个麻将。

最后如果没有数字能成立的话输出no,能成立的话输出能听的牌。枚举完听牌之后输出。

【代码详解】

var

a,b,w:array[1..400]of longint;

m,n,t,i,j,k,tot:longint;

ok:boolean;

begin

readln(n,m);

fori:= 1 to m*3+1 do

begin

read(t);

inc(a[t]);  //a数组用来记录每个数出现的次数

end;

tot:=0;

fori:= 1 to n do   //枚举听牌

begin

inc(a[i]);  //把枚举的数加上

for j:= 1 to n do

if a[j]>=2 then  //枚举将

begin

b:=a;  //我们用数组b来判断,防止a数组弄乱

b[j]:=b[j]-2;  //减去将

ok:=true;  //先将ok的值记为true

for k:= 1 to n do //从头到尾来模拟能否胡

begin

b[k]:=b[k] mod 3;//减掉刻子

if (k+2>n)and(b[k]<>0) then{k+2>n证明这已经是倒数第二个数或者最后一个,后面已经不能有两个数了,}

begin

ok:=false;  //但如果此时它仍然不为0的话证明肯定胡不了

break;  //胡不了所以退出,来枚举另一个将

end;

if (b[k+1]<b[k])or(b[k+2]<b[k]) then//后面两个数的次数任何一个比它大都不可能胡

begin

ok:=false;

break;

end;

b[k+1]:=b[k+1]-b[k];

b[k+2]:=b[k+2]-b[k];

end;

if ok then break;

end;

dec(a[i]);//把刚刚枚举的听牌还原

if ok then  //如果能胡的话记录

begin

inc(tot);

w[tot]:=i;

end;

end;

iftot=0 then writeln(‘NO‘) else

begin

fori:= 1 to tot-1 do

write(w[i],‘ ‘);

writeln(w[tot]);

end;

end.

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

时间: 2024-08-07 22:28:28

JSOI2007 麻将 题解的相关文章

BZOJ 1028: [JSOI2007]麻将 暴力

1028: [JSOI2007]麻将 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1028 Description 麻将是中国传统的娱乐工具之一.麻将牌的牌可以分为字牌(共有东.南.西.北.中.发.白七种)和序数牌(分为条子.饼子.万子三种花色,每种花色各有一到九的九种牌),每种牌各四张.在麻将中,通常情况下一组和了的牌(即完成的牌)由十四张牌组成.十四张牌

【BZOJ 1028】 [JSOI2007]麻将

1028: [JSOI2007]麻将 Time Limit: 1 Sec  Memory Limit: 162 MB Submit: 1076  Solved: 480 [Submit][Status] Description 麻将是中国传统的娱乐工具之一.麻将牌的牌可以分为字牌(共有东.南.西.北.中.发.白七种)和序数牌(分为条子.饼子.万子三种花色,每种花色各有一到九的九种牌),每种牌各四张.在麻将中,通常情况下一组和了的牌(即完成的牌)由十四张牌组成.十四张牌中的两张组成对子(即完全相同

bzoj千题计划118:bzoj1028: [JSOI2007]麻将

http://www.lydsy.com/JudgeOnline/problem.php?id=1028 枚举等待牌 枚举对是哪个 判断 #include<cstdio> #include<iostream> using namespace std; int sum[405],a[405]; int ans[405],tot; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar();

bzoj 1860: [Zjoi2006]Mahjong麻将 题解

[原题] 1860: [Zjoi2006]Mahjong麻将 Time Limit: 1 Sec  Memory Limit: 64 MB Submit: 211  Solved: 122 [Submit][Status] Description Input 第一行一个整数N(N<=100),表示玩了N次超级麻将. 接下来N行.每行100个数a1..a100,描写叙述每次玩牌手中各种牌的数量.ai表示数字为i的牌有ai张.(0<=ai<=100) Output 输出N行,若胡了则输出Ye

【BZOJ】1028: [JSOI2007]麻将(贪心+暴力)

http://www.lydsy.com/JudgeOnline/problem.php?id=1028 表示不会贪心QAQ 按顺序枚举,如果能形成刻子那么就形成刻子,否则形成顺子.orz 证明?:因为按顺序枚举,所以当枚举到i,i一定要用完,所以因为>3个顺子和>3个刻子等价,所以考虑<3个顺子.如果i是刻子,假设我们用顺子,那么显然会剩下<=2个,因此不是最优的,所以有刻子就用刻子. 那么暴力枚举添加的,然后暴力枚举哪个是对子,最后暴力判断..n^3.. #include &l

[JSOI2007]麻将

Description 麻将是中国传统的娱乐工具之一.麻将牌的牌可以分为字牌(共有东.南.西.北.中.发.白七种)和序数 牌(分为条子.饼子.万子三种花色,每种花色各有一到九的九种牌),每种牌各四张.在麻将中,通常情况下一 组和了的牌(即完成的牌)由十四张牌组成.十四张牌中的两张组成对子(即完全相同的两张牌),剩余的十二张 组成三张一组的四组,每一组须为顺子(即同花色且序数相连的序数牌,例如条子的三.四.五)或者是刻子(即 完全相同的三张牌).一组听牌的牌是指一组十三张牌,且再加上某一张牌就可以

[bzoj1028] [JSOI2007]麻将

Description 麻将是中国传统的娱乐工具之一.麻将牌的牌可以分为字牌(共有东.南.西.北.中.发.白七种)和序数牌(分为条子.饼子.万子三种花色,每种花色各有一到九的九种牌),每种牌各四张.在麻将中,通常情况下一组和了的牌(即完成的牌)由十四张牌组成.十四张牌中的两张组成对子(即完全相同的两张牌),剩余的十二张组成三张一组的四组,每一组须为顺子(即同花色且序数相连的序数牌,例如条子的三.四.五)或者是刻子(即完全相同的三张牌).一组听牌的牌是指一组十三张牌,且再加上某一张牌就可以组成和牌

bzoj 1028: [JSOI2007]麻将

暴力枚举+贪心 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<queue> 7 #include<map> 8 #include<cmath> 9 #define M 100009 10 #define ll long long 11

[BZOJ 1028] [JSOI2007] 麻将 【枚举+贪心判断】

题目链接:BZOJ - 1028 题目分析 枚举听的是哪种牌,再枚举成对的是哪种牌,再贪心判断: 从1到n枚举每一种牌,如果这种牌的个数小于0,就返回不合法. 将这种牌的张数 % 3, 剩下的只能和 i + 1, i + 2 这两种牌构成顺,所以 Num[i + 1] -= Num[i]; Num[i + 2] -= Num[i]; 牌的种类要枚举到 n + 2,因为第 n - 1 和第 n 种牌可能会减掉 n + 1,n + 2 的牌. 代码 #include <iostream> #inc