[JSOI2007]麻将

嘟嘟嘟

 

遇到这种题,再看看这数据范围,一般都是暴力。

然而暴力也是有差别的,比如我写的那个,代码悠长有让人看不懂,而且最终还没过,看了点题解的思路,发现我有很多情况都重复了,导致不仅时间复杂度无法保证,而且正确性还待考察。

 

首先,我们从1到n枚举等待牌,然后在枚举对子,接着在枚举刻子,最后看看能否凑成顺子。为啥先看刻子再看顺子咧,因为三张相同的顺子就是三张刻子,而且对于一种牌,刻子取完后剩下的牌一定用来构成顺子,减少了枚举情况。

具体的做法就是开一个类似桶的数组,记录每种数字牌有多少个,然后枚举刻子的时候就是num[i] % 3,若还剩下,那么一定用来构成顺子,然后判断这张牌一下能否构成顺子,不能就说明当前枚举的等待牌不对。

刚开始我是这么想的,记录顺子和刻子个数,然后看最后是和否等于m,其实没必要,因为只有14张牌,除了对子剩下的牌都用来构成顺子或刻子,所以如果哪一张牌构不成顺子或刻子,就说明这套牌不能和。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<cctype>
 8 #include<stack>
 9 #include<queue>
10 #include<vector>
11 using namespace std;
12 #define enter puts("")
13 #define space putchar(' ')
14 #define Mem(a) memset(a, 0, sizeof(a))
15 typedef long long ll;
16 typedef double db;
17 const int INF = 0x3f3f3f3f;
18 const db eps  =1e-8;
19 const int maxn = 3e3 + 5;
20 inline ll read()
21 {
22     ll ans = 0;
23     char ch = getchar(), last = ' ';
24     while(!isdigit(ch)) {last = ch; ch = getchar();}
25     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
26     if(last == '-') ans = -ans;
27     return ans;
28 }
29 inline void write(ll x)
30 {
31     if(x < 0) putchar('-'), x = -x;
32     if(x >= 10) write(x / 10);
33     putchar(x % 10 + '0');
34 }
35 
36 int n, m, N, a[maxn];
37 int num[maxn], ntp[maxn];
38 
39 bool judge()
40 {
41     for(int i = 1; i <= n; ++i)
42     {
43         ntp[i] %= 3;
44         if(ntp[i])
45         {
46             if(i + 2 > n) return 0;
47             for(int j = i + 1; j <= i + 2; ++j)
48             {
49                 ntp[j] -= ntp[i]; 
50                 if(ntp[j] < 0) return 0;
51             }
52 //            if(--ntp[i + 1] < 0) return 0;        //刚开始这么写的,但可能剩下的有两张牌,都得用来构成顺子 
53 //            if(--ntp[i + 2] < 0) return 0;
54         }
55     }
56     return 1;
57 }
58 
59 int main()
60 {
61     n = read(); m = read();
62     for(int i = 1; i <= 3 * m + 1; ++i) {int x = read(); num[x]++;}
63     bool flag = false;
64     for(int i = 1; i <= n; ++i)
65     {
66         num[i]++;
67         for(int j = 1; j <= n; ++j)        //枚举对子 
68         {
69             for(int k = 1; k <= n; ++k) ntp[k] = num[k];
70             ntp[j] -= 2; if(ntp[j] < 0) continue;    
71             if(judge()) {flag = 1; write(i); space; break;}
72         }
73         num[i]--;
74     }
75     if(!flag) printf("NO\n"); 
76     return 0;
77 }
View Code

 

posted @ 2018-08-17 17:36  mrclr  阅读(163)  评论(0编辑  收藏  举报