• [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 }
  • 相关阅读:
    红楼【建筑位置】
    红楼【人物关系】
    jenkins【shared-libraries】
    linux 安装mysql8.0 tar.xz
    MySQL 输入字符串对日期进行模糊查询
    解决kali linux 和 win10 双系统时间不一致问题
    linux idea桌面图标
    linux卸载openjdk11
    tar.xz解压
    pandas模块高性能使用方法总结
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/7257368.html
Copyright © 2020-2023  润新知