zoukankan      html  css  js  c++  java
  • codevs2464超级麻将

    题目链接http://codevs.cn/problem/2464/

    题目描述 Description

    很多人都知道玩麻将,当然也有人不知道,呵呵,不要紧,我在这里简要地介绍一下麻将规则:
    普通麻将有砣、索、万三种类型的牌,每种牌有 1~9个数字,其中相同的牌
    每个有四张,例如 1 砣~9 砣,1索~9 索,1 万~9 万各有 4 张,所以共 36*3=108张牌。胡牌时每人有 14 张牌,其中只要某人手里有若干句话(就是同种类型的牌连续三张或同种牌三张) ,另外再加上一对,即可胡牌。当然如果全是对,叫七小对,也可以胡牌。下图是连三张示例。

    四万 五万 六万

    四万 四万 四万

    要判断某人是否胡牌,显然一个弱智的算法就行了,某中学信息学小组超级麻将迷想了想,决定将普通麻将改造成超级麻将。
    所谓超级麻将没有了砣、索、万的区分,每种牌上的数字可以是 1~100,而每种数字的牌各有100 张。另外特别自由的是,玩牌的人手里想拿多少张牌都可以,好刺激哦!
    刺激归刺激,但是拿多了怎么胡牌呢?
    超级麻将规定只要一个人手里拿的牌是若干句话(三个连续数字的牌各一张组成一句话,三张或者四张同样数字的牌也算一句话) ,再加上一对相同的牌,就算胡了。
    作为信息学竞赛选手的你,麻烦你给这位超级麻将迷编个程序,判断能否胡牌。

    输入描述 Input Description

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

    输出描述 Output Description

       输出 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

    感想:

    怎么样,刚看到题目的你是不是一辆懵逼?不知所措?其实啊,我一开始也是这样(写了一个dfs,结果0分)后来在自(da)己(shen)的(de)思(bang)考(zhu)下,在做出这道题。

    题解:

    首先,我们要仔细读题,发现有如下这几种操作:

    1. 一种牌的个数-3
    2. 一种牌的个数-4
    3. 连续3种牌的个数-1
    4. 连续3种牌的个数-2

    也许你很奇怪,不是可以再继续三种牌减下去吗(如:-4,-5)?但有没有发现三种牌-4相当于每种牌都用了一次操作2,-5相当于每种牌都用了一次操作2有用了一次操作3!以此类推,我们可以发现,一共只有如上这4种操作。

    于是,我们可以先处理出一个ok数组,ok[i][j]表示i-j的差能否用操作1和操作2完成(相当于一个背包)

    接下来,就是激动人心的DP啦!

    f[i][j][k]代表到第i种牌为止,有j张i-1种牌,k张i种牌是否可行(即判断f[i][j][k]是否为true)

    而此时,我们会发现,还要处理多出来的两张牌的情况!!!!!!!!!!!!!!这是一个棘手的问题,但我们可以在数组后面多开一维l,表示当前是否已经出现有两张的牌的情况(即l=1或l=0)。

    然后,我们就可以利用ok数组和我们上面推出来的操作进行DP啦!

    代码

    #include <cstdio>
    #include <cstring>
    using namespace std;
    int i,j,k,n,m,x,y,t,T,a[105],p;
    bool dp[105][105][105][2],ok[105][3];
    void read(int &d){
    d=0;int f=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9'){d=d*10+ch-'0';ch=getchar();}
    d=d*f;
    }
    int main(){
    memset(ok,0,sizeof ok);
    for (i=0;i<=100;i++)
    for (j=0;j<=2;j++)
    for (k=0;k<=(i-j)/3;k++)
    if ((i-j-3*k)%4==0)ok[i][j]=1;
    read(T);
    while (T--){
    for (i=1;i<=100;i++)read(a[i]);
    memset(dp,0,sizeof dp);
    dp[2][a[1]][a[2]][0]=1;
    for (i=2;i<=99;i++)
    for (j=0;j<=a[i-1];j++)
    for (k=0;k<=a[i];k++){
    for (p=0;p<=1;p++){
    if (ok[j][0])dp[i+1][k][a[i+1]][p]|=dp[i][j][k][p];
    if (ok[j][1]&&a[i+1]>0&&k>0)dp[i+1][k-1][a[i+1]-1][p]|=dp[i][j][k][p];
    if (ok[j][2]&&a[i+1]>1&&k>1)dp[i+1][k-2][a[i+1]-2][p]|=dp[i][j][k][p];
    }
    if (j>=2){
    if (ok[j-2][0])dp[i+1][k][a[i+1]][1]|=dp[i][j][k][0];
    if (ok[j-2][1]&&k>0&&a[i+1]>0)dp[i+1][k-1][a[i+1]-1][1]|=dp[i][j][k][0];
    if (ok[j-2][2]&&k>1&&a[i+1]>1)dp[i+1][k-2][a[i+1]-2][1]|=dp[i][j][k][0];
    }
    }
    bool flag=false;
    for (i=0;i<=a[99];i++)if (ok[i][0])for (j=0;j<=a[100];j++)if (ok[j][0])flag|=dp[100][i][j][1];
    for (i=0;i<=a[99];i++)if (ok[i][0])for (j=0;j<=a[100];j++)if (ok[j-2][0]&&j>=2)flag|=dp[100][i][j][0];
    for (i=0;i<=a[99];i++)if (ok[i-2][0]&&i>=2)for (j=0;j<=a[100];j++)if (ok[j][0])flag|=dp[100][i][j][0];
    if (flag)printf("Yes
    ");else printf("No
    ");
    }
    return 0;
    }
    
  • 相关阅读:
    卡特兰数
    hdu 1023 Train Problem II
    hdu 1022 Train Problem
    hdu 1021 Fibonacci Again 找规律
    java大数模板
    gcd
    object dection资源
    Rich feature hierarchies for accurate object detection and semantic segmentation(RCNN)
    softmax sigmoid
    凸优化
  • 原文地址:https://www.cnblogs.com/Acheing/p/6786390.html
Copyright © 2011-2022 走看看