麻将

来源:互联网 发布:java b2c商城系统源码 编辑:程序博客网 时间:2024/04/20 10:34

【问题描述】

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

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

Input

【输入】

输入文件名为mahjong.in。

包含两行。

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

Output

【输出】

输出文件名为mahjong.out。

输出为一行。

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

Sample Input

9 4

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

Sample Output

6 7 9

Data Constraint

Hint

【数据范围】

10%满足n≤13,m≤20。

100%满足9<=n<=400, 4<=m<=1000。

分析:
【解题思路】

一、枚举胡的牌,枚举哪个当一对,从左到右简单贪心扫描一遍即可,贪心是指可以取刻子的就取刻子,剩下的去顺子,O(n^3)。
二、枚举胡的牌,f[I,p,j,k]:i=0表示已找到了对子,i=1表示没找到,已计算了前p位,p+1等价于有j张牌,p+2等价于有k张牌的情况是否可能出现。 O(n^2)
三、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 n,m,i,j,k,x,c:longint; a,b:array [1..403] of longint; flag,flag1:boolean;begin readln(n,m); for i:=1 to 3*m+1 do  begin   read(x);   inc(a[x]);  end; flag1:=false; for i:=1 to n do  begin   for j:=1 to n do    begin     b:=a;     b[i]:=b[i]+1;     if b[j]<2 then continue;     b[j]:=b[j]-2;     flag:=true;     for k:=1 to n+2 do      begin       if b[k]<0 then        begin         flag:=false;         break;        end;       b[k]:=b[k] mod 3;       b[k+1]:=b[k+1]-b[k];       b[k+2]:=b[k+2]-b[k];      end;     if flag then begin      write(i,' '); flag1:=true; break;      end;    end;  end; if flag1=false then  write('NO');end.
0 0