• [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
    "); 
    76     return 0;
    77 }
    View Code
  • 相关阅读:
    汽车加油问题--贪心算法
    区间相交问题---贪心算法
    算法-动态规划-数字三角问题
    jar转成exe
    kafka zookeeper学习(2) 测试kafka与zookeeper环境
    kafka zookeeper学习(1) windows搭建kafka与zookeeper环境
    java调用linux系统命令
    linux hg(mercurial)入门
    redis集群构建过程 linux windows
    Java JTextArea不能实时刷新的问题
  • 原文地址:https://www.cnblogs.com/mrclr/p/9494561.html
Copyright © 2020-2023  润新知