zoukankan      html  css  js  c++  java
  • [ZJOI 2006]超级麻将

    Description

    Input

    第一行一个整数N(N<=100),表示玩了N次超级麻将。 接下来N行,每行100个数a1..a100,描述每次玩牌手中各种牌的数量。ai表示数字为i的牌有ai张。(0<=ai<=100)

    Output

    输出N行,若胡了则输出Yes,否则输出No,注意区分Yes,No的大小写!

    Sample Input

    3
    2 4 0 0 0 0 0 …… 0(一共98个0)
    2 4 2 0 0 0 0 …… 0(一共97个0)
    2 3 2 0 0 0 0 …… 0(一共97个0)

    Sample Output

    Yes
    Yes
    No

    题解

    这道题题解很多都是用贪心+$Hash$搜索做的,其实$DP$也可以解决这道题。

    我们考虑选取麻将的先后是不互相影响的。且怎么选当前牌只会影响其相邻的几张牌,我们将这些影响的状态放入方程中,保证无后效性。

    令: $f[i][j][k][0/1]$ 表示“择第 $i$ 号牌时,第 $i-1$ 号牌要打出 $j$ 张,第 $i$ 号牌要打出 $k$ 张,之前选的所有牌是否( $0/1$ )选择了将(对子)”是否可行。

    于是就有转移方程:

    1. 考虑选这i号牌做将(对子):
      if (k>1) f[i][j][k][1]|=f[i][j][k-2][0];
    2. 考虑i号牌碰(三张相同):
      if (k>2) f[i][j][k][1]|=f[i][j][k-3][1],f[i][j][k][0]|=f[i][j][k-3][0];
    3. 考虑i号牌杠(四张相同):
      if (k>3) f[i][j][k][1]|=f[i][j][k-4][1],f[i][j][k][0]|=f[i][j][k-4][0];
    4. 考虑i-2,i-1,i三张牌吃(三个连续数字):
      if (j>=k&&a[i-2]>=k) f[i][j][k][0]|=f[i-1][a[i-2]-k][j-k][0],f[i][j][k][1]|=f[i-1][a[i-2]-k][j-k][1];

    最后结果为$f[100][a[99]][a[100]][1]$。

    附的代码有个玄学的写法:当$i==1$时,$a[i-2]$越界?我也不知道它访问到哪去了,但$AC$了就苟活着吧。

    人生处处是惊喜...难道不是吗?

     1 #include<set>
     2 #include<map>
     3 #include<ctime>
     4 #include<cmath>
     5 #include<queue>
     6 #include<stack>
     7 #include<cstdio>
     8 #include<string>
     9 #include<vector>
    10 #include<cstring>
    11 #include<cstdlib>
    12 #include<iostream>
    13 #include<algorithm>
    14 #define LL long long
    15 #define RE register
    16 #define IL inline
    17 using namespace std;
    18 
    19 int n,a[105];
    20 bool f[105][105][105][2];
    21 
    22 int main()
    23 {
    24     scanf("%d",&n);
    25     while (n--)
    26     {
    27         memset(f,0,sizeof(f));
    28         for (RE int i=1;i<=100;i++) scanf("%d",&a[i]);
    29         f[0][0][0][0]=1;
    30         for (RE int i=1;i<=100;i++)
    31             for (RE int j=0;j<=a[i-1];j++)
    32                 for (RE int k=0;k<=a[i];k++)
    33                 {
    34                     if (k>1) f[i][j][k][1]|=f[i][j][k-2][0];
    35                     if (k>2) f[i][j][k][1]|=f[i][j][k-3][1],f[i][j][k][0]|=f[i][j][k-3][0];
    36                     if (k>3) f[i][j][k][1]|=f[i][j][k-4][1],f[i][j][k][0]|=f[i][j][k-4][0];
    37                     if (j>=k&&a[i-2]>=k) f[i][j][k][0]|=f[i-1][a[i-2]-k][j-k][0],f[i][j][k][1]|=f[i-1][a[i-2]-k][j-k][1];
    38                 }
    39         printf(f[100][a[99]][a[100]][1] ? "Yes
    ":"No
    ");
    40     }
    41     return 0;
    42 }
  • 相关阅读:
    WinDbg 调试工具的使用
    多线程间通信之AutoResetEvent和ManualResetEvent的原理分析和开发示例
    Oracle Database 11g Release 2 (11.2) Installation On Oracle Linux 6
    软件项目管理解决方案(转)
    iis应用程序池 内存溢出错误 System.OutOfMemoryException(转)
    今天遇到Oracle审计表AUD$数据过大问题
    从完好的数据文件恢复oracle数据库
    ORA12518 TNS:监听程序无法分发客户机连接 解决办法(转)
    RHEL 5防火墙说明
    example how to build RPM package from source package
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/7257368.html
Copyright © 2011-2022 走看看