洛谷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\n");
        else printf("No\n");
    }
    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\n");
        else printf("No\n");
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Zinn/p/9369899.html