zoukankan      html  css  js  c++  java
  • 洛谷P2593 [ ZJOI 2006 ] 超级麻将 —— DP

    题目:https://www.luogu.org/problemnew/show/P2593

    DP的话,考虑到当前这一位只跟前两位有关,所以记录一下这3位的状态就行;

    于是一开始记录的第 i 位,i-1 位的数量,i-2 位的数量,是否有过对子,然后可行性DP;

    但是写得太丑,又WA又T...

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int n,a[105];
    bool f[105][105][105][3];
    int rd()
    {
        int ret=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
        return ret*f;
    }
    int main()
    {
        scanf("%d",&n);
        while(n--)
        {
            memset(a,0,sizeof a);
            memset(f,0,sizeof f);
            for(int i=1;i<=100;i++)a[i]=rd();
            f[0][0][0][0]=1;
            for(int i=1;i<=100;i++)
                for(int j=0;j<=(i-2>0?a[i-2]:0);j++)
                    for(int k=j;k<=(i-1>0?a[i-1]:0);k++)    if(f[i-1][j][k][0]||f[i-1][j][k][1])
                    {
                        if(a[i]>=j)f[i][k-j][a[i]-j][0]=f[i-1][j][k][0];
                        if(a[i]>=j)f[i][k-j][a[i]-j][1]=f[i-1][j][k][1];
                        if(a[i]-j>=2&&f[i-1][j][k][0])f[i][k-j][a[i]-j-2][1]=1; 
                        for(int l=1;a[i]-j>=3*l;l++)
                        {
                            if(a[i]-j>=3*l)
                            {
                                f[i][k-j][a[i]-j-3*l][0]=f[i-1][j][k][0];
                                f[i][k-j][a[i]-j-3*l][1]=f[i-1][j][k][1];
                            }
                            if(a[i]-j>=4*l)
                            {
                                f[i][k-j][a[i]-j-4*l][0]=f[i-1][j][k][0];
                                f[i][k-j][a[i]-j-4*l][1]=f[i-1][j][k][1];
                            }
                        }
                    }
            if(f[100][0][0][1])printf("Yes
    ");
            else printf("No
    ");
        }
        return 0;
    }

    于是放弃这个写法了...

    看到TJ,记录的是第 i 位和第 i-1 位的数量,这样就可以同层转移啦!于是简洁好多;

    但总感觉复杂度有点不对啊,这样最高不是 10^8 吗...总之加上 register 就卡过去了。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int n,a[105];
    bool f[105][105][105][3];
    int rd()
    {
        int ret=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
        return ret*f;
    }
    int main()
    {
        n=rd();
        while(n--)
        {
            memset(f,0,sizeof f);
            for(register int i=1;i<=100;i++)a[i]=rd();
            f[0][0][0][0]=1;
            for(register int i=1;i<=100;i++)
                for(register int j=0;j<=(i-1>0?a[i-1]:0);j++)
                    for(register int k=0;k<=a[i];k++)
                    {
                        if(k>=2)f[i][j][k][1]|=f[i][j][k-2][0];//可以同层转移囧 
                        if(k>=3)f[i][j][k][0]|=f[i][j][k-3][0],f[i][j][k][1]|=f[i][j][k-3][1];
                        if(k>=4)f[i][j][k][0]|=f[i][j][k-4][0],f[i][j][k][1]|=f[i][j][k-4][1];
                        if(k<=j&&k<=a[i-2])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];
                    }
            if(f[100][a[99]][a[100]][1])printf("Yes
    ");
            else printf("No
    ");
        }
        return 0;
    }
  • 相关阅读:
    洛谷—— P3353 在你窗外闪耀的星星
    洛谷—— P1238 走迷宫
    洛谷—— P1262 间谍网络
    9.8——模拟赛
    洛谷—— P1189 SEARCH
    算法
    May 22nd 2017 Week 21st Monday
    May 21st 2017 Week 21st Sunday
    May 20th 2017 Week 20th Saturday
    May 19th 2017 Week 20th Friday
  • 原文地址:https://www.cnblogs.com/Zinn/p/9369899.html
Copyright © 2011-2022 走看看