• 【BZOJ】【1028】【JSOI2007】麻将


    暴力/模拟


      $nleq400$,嗯……这是一个很小的数据范围= =

      判断一副牌是不是听牌并求出听什么牌太麻烦了,干脆我们直接判是不是胡牌好了~

      枚举胡的是哪张牌,然后判一下加上这张牌后是否能胡。

      算法框架很好写:

    1 F(i,1,n){
    2     a[i]++;
    3     if (check()) ans[++tot]=i;
    4     a[i]--;
    5 }

      但是这个check怎么写让我很蛋疼……

     1 int n,m,a[N],b[N],ans[N],tot;
     2 bool dfs(int x){
     3     if (x==n+1 && b[x]==0 && b[x+1]==0) return 1;
     4     if (b[x]==0) return dfs(x+1);
     5     if (b[x]<0) return 0;
     6     bool ans=0;
     7     for(int i=b[x];i>=0;i-=3){
     8         b[x+1]-=i; b[x+2]-=i;
     9         if (dfs(x+1)) return 1;
    10         b[x+1]+=i; b[x+2]+=i;
    11     }
    12     return 0;
    13 }
    14 bool check(){
    15     F(i,1,n) b[i]=a[i];
    16     F(i,1,n)
    17         if (b[i]>=2){
    18             b[i]-=2;
    19             if (dfs(1)) return 1;
    20             b[i]+=2;
    21         }
    22     return 0;
    23 }
    dfs爆搜版(TLE了2个点,80分)

      其实大胆猜想一下,可以得到一个更优的方案:每种牌优先考虑成刻子,剩余的再考虑成顺子(Orz Hzwer)

     1 bool check(){
     2     bool flag;
     3     F(i,1,n)
     4         if (a[i]>=2){
     5             flag=1;
     6             a[i]-=2;
     7             F(i,1,n+2) b[i]=a[i];
     8             F(j,1,n+2){
     9                 if (b[j]<0){flag=0;break;}
    10                 b[j]%=3;
    11                 b[j+1]-=b[j];
    12                 b[j+2]-=b[j];
    13             }
    14             a[i]+=2;
    15             if (flag) return 1;
    16         }
    17     return 0;
    18 }
    $N^3$快速版(AC)

    代码:

     1 /**************************************************************
     2     Problem: 1028
     3     User: Tunix
     4     Language: C++
     5     Result: Accepted
     6     Time:308 ms
     7     Memory:1276 kb
     8 ****************************************************************/
     9  
    10 //BZOJ 1028
    11 #include<cstdio>
    12 #include<cstring>
    13 #include<cstdlib>
    14 #include<iostream>
    15 #include<algorithm>
    16 #define rep(i,n) for(int i=0;i<n;++i)
    17 #define F(i,j,n) for(int i=j;i<=n;++i)
    18 #define D(i,j,n) for(int i=j;i>=n;--i)
    19 using namespace std;
    20 typedef long long LL;
    21 inline int getint(){
    22     int r=1,v=0; char ch=getchar();
    23     for(;!isdigit(ch);ch=getchar()) if(ch=='-')r=-1;
    24     for(; isdigit(ch);ch=getchar()) v=v*10+ch-'0';
    25     return r*v;
    26 }
    27 const int N=410;
    28 /*******************template********************/
    29 int n,m,a[N],b[N],ans[N],tot;
    30 bool check(){
    31     bool flag;
    32     F(i,1,n)
    33         if (a[i]>=2){
    34             flag=1;
    35             a[i]-=2;
    36             F(i,1,n+2) b[i]=a[i];
    37             F(j,1,n+2){
    38                 if (b[j]<0){flag=0;break;}
    39                 b[j]%=3;
    40                 b[j+1]-=b[j];
    41                 b[j+2]-=b[j];
    42             }
    43             a[i]+=2;
    44             if (flag) return 1;
    45         }
    46     return 0;
    47 }
    48 int main(){
    49 #ifndef ONLINE_JUDGE
    50     freopen("1028.in","r",stdin);
    51 //  freopen("1028.out","w",stdout);
    52 #endif
    53     n=getint(); m=getint();
    54     F(i,1,3*m+1) a[getint()]++;
    55     F(i,1,n){
    56         a[i]++;
    57         if (check()) ans[++tot]=i;
    58         a[i]--;
    59     }
    60     if (!tot){printf("NO");return 0;}
    61     F(i,1,tot) {printf("%d",ans[i]); if(i!=tot) printf(" ");}
    62     return 0;
    63 }
    View Code

    1028: [JSOI2007]麻将

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 1158  Solved: 519
    [Submit][Status][Discuss]

    Description

    麻 将是中国传统的娱乐工具之一。麻将牌的牌可以分为字牌(共有东、南、西、北、中、发、白七种)和序数牌(分为条子、饼子、万子三种花色,每种花色各有一到 九的九种牌),每种牌各四张。在麻将中,通常情况下一组和了的牌(即完成的牌)由十四张牌组成。十四张牌中的两张组成对子(即完全相同的两张牌),剩余的 十二张组成三张一组的四组,每一组须为顺子(即同花色且序数相连的序数牌,例如条子的三、四、五)或者是刻子(即完全相同的三张牌)。一组听牌的牌是指一 组十三张牌,且再加上某一张牌就可以组成和牌。那一张加上的牌可以称为等待牌。  在这里,我们考虑一种特殊的麻将。在这种特殊的麻将里,没有字牌,花色 也只有一种。但是,序数不被限制在一到九的范围内,而是在1到n的范围内。同时,也没有每一种牌四张的限制。一组和了的牌由3m + 2张牌组成,其中两张组成对子,其余3m张组成三张一组的m组,每组须为顺子或刻子。现给出一组3m + 1张的牌,要求判断该组牌是否为听牌(即还差一张就可以和牌)。如果是的话,输出所有可能的等待牌。

    Input

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

    Output

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

    Sample Input

    9 4
    1 1 2 2 3 3 5 5 5 7 8 8 8

    Sample Output

    6 7 9

    HINT

    Source

    [Submit][Status][Discuss]
  • 相关阅读:
    reactnative 遍历本地图片地址,及避坑
    reactnative 类父组件调用子函数组件的方法
    reactnativesvg 使用
    reactnative 监听返回事件
    reactnative 使用日历 reactnativecommondatepicker
    reactnative Teaset微提示
    reactnative 子组件中进行路由跳转
    reactnative mobx状态管理
    reactnative类父组件调用类子组件的方法
    reactnative 实现阴影效果
  • 原文地址:https://www.cnblogs.com/Tunix/p/4424474.html
Copyright © 2020-2023  润新知