• 洛谷 1155 (NOIp2008)双栈排序——仔细分析不合法的条件


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

    这道题教会我们要多思考。

    好好分析过后发现同一个栈里不能有升序。就用它写了一个30分。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N=1005;
    int n,stack[2][N],top[2],nw,tot,ps[N];
    char ch[N<<1];
    bool flag;
    int main()
    {
        scanf("%d",&n);int x;nw=1;
        stack[0][0]=stack[1][0]=n+1;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&x);
            if(stack[0][top[0]]>x){
                stack[0][++top[0]]=x;
                ch[++tot]='a';ps[x]=1;
            }
            else if(stack[1][top[1]]>x){
                stack[1][++top[1]]=x;
                ch[++tot]='c';ps[x]=2;
            }
            else {
                flag=1;break;
            }
            while(ps[nw])
            {
                if(ps[nw]==1){
                    top[0]--;ch[++tot]='b';
                }
                else{
                    top[1]--;ch[++tot]='d';
                }
                nw++;
            }
        }
        if(flag)printf("0");
        else for(int i=1;i<=tot;i++)printf("%c ",ch[i]);
        return 0;
    }
    View Code

    然后发现只有30分。想想自己想得太简单了。于是写了个深搜30分。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N=1005;
    int n,stack[2][N],top[2],tot,ps[N],a[N];
    char ch[N<<1];
    bool flag;
    void rd(int x,int k)
    {
        stack[k][++top[k]]=x;ch[++tot]=(k?'c':'a');ps[x]=k+1;
    //    printf("stack%d=%d(top[k]=%d)
    ",k,stack[k][top[k]],top[k]);
    }
    void clr(int x,int k)
    {
        top[k]--;tot--;ps[x]=0;
    }
    void cd(int &nw)
    {
    //    printf("cd!
    ");
        while(ps[nw])
        {
            if(ps[nw]==1){
                top[0]--;ch[++tot]='b';
            }
            else{
                top[1]--;ch[++tot]='d';
            }
            nw++;
        }
    }
    void dfs(int cr,int nw)
    {
        if(cr>n)return;
        int x=a[cr],tnw=nw;bool cflag=0;
        int tsk[2][N];memcpy(tsk,stack,sizeof stack);
        if(stack[0][top[0]]>x&&stack[1][top[1]]<x)
        {
            rd(x,0);
            if(ps[nw])cflag=1,cd(nw);
    //        printf("cr=%d 0
    ",cr);
            dfs(cr+1,nw);
            if(flag){
                if(cflag){
                    tot-=nw-tnw;top[0]+=nw-tnw;nw=tnw;
                    memcpy(stack,tsk,sizeof tsk);
                }
                clr(x,0);
    //            printf("ret cr=%d flag=1
    ",cr);
            }
        }
        else if(stack[1][top[1]]>x&&stack[0][top[0]]<x)
        {
            rd(x,1);
            if(ps[nw])cflag=1,cd(nw);
    //        printf("cr=%d 1
    ",cr);
            dfs(cr+1,nw);
            if(flag){
                if(cflag){
                    tot-=nw-tnw;top[1]+=nw-tnw;nw=tnw;
                    memcpy(stack,tsk,sizeof tsk);
                }
                clr(x,1);
    //            printf("ret cr=%d flag=1
    ",cr);
            }
        }
        else if(stack[1][top[1]]<x&&stack[0][top[0]]<x)
        {
    //        printf("cr=%d flag=1!
    ",cr);
            flag=1;return;
        }
        else{
    //        printf("stack0=%d stack1=%d(top0=%d top1=%d)
    ",stack[0][top[0]],stack[1][top[1]],top[0],top[1]);
            rd(x,0);
            if(ps[nw])cflag=1,cd(nw);
    //        printf("cr=%d try0
    ",cr);
            dfs(cr+1,nw);
            if(flag){
                if(cflag){
                    tot-=nw-tnw;top[0]+=nw-tnw;nw=tnw;
                    memcpy(stack,tsk,sizeof tsk);
                }
                clr(x,0);
    //            printf("cr=%d failtry0 try1
    ",cr);
                flag=0;cflag=0;rd(x,1);
                if(ps[nw])cflag=1,cd(nw);
                dfs(cr+1,nw);
                if(flag){
                    if(cflag){
                        tot-=nw-tnw;top[1]+=nw-tnw;nw=tnw;
                        memcpy(stack,tsk,sizeof tsk);
                    }
                    clr(x,1);
    //                printf("cr=%d failtry1
    ",cr);
                }
            }
        }
    }
    int main()
    {
        scanf("%d",&n);int x;
        stack[0][0]=stack[1][0]=n+1;
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        dfs(1,1);
        if(flag)printf("0");
        else for(int i=1;i<=tot;i++)printf("%c ",ch[i]);
        return 0;
    }
    View Code

    然后发现只有30分。那就剪剪枝吧。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N=1005;
    int n,stack[2][N],top[2],tot,ps[N],a[N];
    char ch[N<<1];
    bool flag;
    void rd(int x,int k)
    {
        stack[k][++top[k]]=x;ch[++tot]=(k?'c':'a');ps[x]=k+1;
    //    printf("stack%d=%d(top[k]=%d)
    ",k,stack[k][top[k]],top[k]);
    }
    void clr(int x,int k)
    {
        top[k]--;tot--;ps[x]=0;
    }
    void cd(int &nw)
    {
    //    printf("cd!
    ");
        while(ps[nw])
        {
            if(ps[nw]==1){
                top[0]--;ch[++tot]='b';
            }
            else{
                top[1]--;ch[++tot]='d';
            }
            nw++;
        }
    }
    bool check(int cr,int x)
    {
        int i;
        for(i=cr+1;i<=n;i++)if(a[i]>a[cr]&&a[i]>x)break;
        for(int j=i+1;j<=n;j++)if(a[j]<a[cr])return 0;//导致在j之前cr不能弹出 
        return 1;
    }
    void dfs(int cr,int nw)
    {
        if(cr>n)return;
        int x=a[cr],tnw=nw;bool cflag=0;
        int tsk[2][N];memcpy(tsk,stack,sizeof stack);
        if(stack[0][top[0]]>x&&stack[1][top[1]]<x)
        {
            rd(x,0);
            if(ps[nw])cflag=1,cd(nw);
    //        printf("cr=%d 0
    ",cr);
            dfs(cr+1,nw);
            if(flag){
                if(cflag){
                    tot-=nw-tnw;top[0]+=nw-tnw;nw=tnw;
                    memcpy(stack,tsk,sizeof tsk);cflag=0;
                }
                clr(x,0);
    //            printf("ret cr=%d flag=1
    ",cr);
            }
        }
        else if(stack[1][top[1]]>x&&stack[0][top[0]]<x)
        {
            rd(x,1);
            if(ps[nw])cflag=1,cd(nw);
    //        printf("cr=%d 1
    ",cr);
            dfs(cr+1,nw);
            if(flag){
                if(cflag){
                    tot-=nw-tnw;top[1]+=nw-tnw;nw=tnw;
                    memcpy(stack,tsk,sizeof tsk);cflag=0;
                }
                clr(x,1);
    //            printf("ret cr=%d flag=1
    ",cr);
            }
        }
        else if(stack[1][top[1]]<x&&stack[0][top[0]]<x)
        {
    //        printf("cr=%d flag=1!
    ",cr);
            flag=1;return;
        }
        else{
    //        printf("stack0=%d stack1=%d(top0=%d top1=%d)
    ",stack[0][top[0]],stack[1][top[1]],top[0],top[1]);
            if(check(cr,stack[1][top[1]]))
            {
                rd(x,0);
                if(ps[nw])cflag=1,cd(nw);
    //            printf("cr=%d try0
    ",cr);
                dfs(cr+1,nw);
                if(flag){
                    if(cflag){
                        tot-=nw-tnw;top[0]+=nw-tnw;nw=tnw;
                        memcpy(stack,tsk,sizeof tsk);cflag=0;
                    }
                    clr(x,0);
                }
            }
            if(flag&&check(cr,stack[0][top[0]]))
            {
                flag=0;rd(x,1);
                if(ps[nw])cflag=1,cd(nw);
                dfs(cr+1,nw);
                if(flag){
                    if(cflag){
                        tot-=nw-tnw;top[1]+=nw-tnw;nw=tnw;
                        memcpy(stack,tsk,sizeof tsk);cflag=0;
                    }
                    clr(x,1);
    //                printf("cr=%d failtry1
    ",cr);
                }
            }
            if(flag||(!check(cr,stack[0][top[0]])&&!check(cr,stack[1][top[1]])))flag=1;
        }
    }
    int main()
    {
        scanf("%d",&n);int x;
        stack[0][0]=stack[1][0]=n+1;
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        dfs(1,1);
        if(flag)printf("0");
        else for(int i=1;i<=tot;i++)printf("%c ",ch[i]);
        return 0;
    }
    View Code

    然后发现只有30分。而且T1WA6。

    在写搜索之前看了看TJ,体现在最后那个check里。就是如果a[1],a[2],a[3]满足a[2]>a[1],a[3]<a[1]的话,在a[3]来之前a[1]不能出栈,就被堵在了a[2]后面,从而GG。

    但是这竟然就是唯一的GG条件!需要仔细思考。

    这个性质和自己开始分析出来的浅显性质的不同之处:

    1.自己的那个只有在过程中才能判断,因为一开始有升序,也可能前面小的先出栈,后面大的再进来。

      而正解的想法是把这个不确定因素也分析掉,得出如果在这个大的后面又有一个比最前面的更小的,就真的不行了。

        这样就能不在过程中判断而可以预先判断了。

    2.自己对“两个栈”认识不足。明明可以把它看成一个主栈和一个辅助栈,用上一条判断出不能往主栈放就放在辅助栈里,可自己……

      没错,正解这样想的话就可以只关注元素能不能放在同一个栈中。然后想到只有两个栈,于是二分图染色就有了。

    因为判掉了无解,所以最后的模拟可以开放又随便。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N=1005;
    int n,a[N],head[N],xnt,col[N],ps[N],now,f[N];
    bool flag;
    struct Edge{
        int next,to;
        Edge(int n=0,int t=0):next(n),to(t) {}
    }edge[N*N];
    void add(int x,int y)
    {
        edge[++xnt]=Edge(head[x],y);head[x]=xnt;
        edge[++xnt]=Edge(head[y],x);head[y]=xnt;
    }
    void init()
    {
        f[n]=n+1;
        for(int i=n-1;i;i--)
        {
            f[i]=min(f[i+1],a[i+1]);
            for(int j=i+1;j<=n;j++)
                if(a[j]>a[i]&&f[j]<a[i])add(i,j);
        }
    }
    void dfs(int cr)
    {
        for(int i=head[cr],v;i;i=edge[i].next)
        {
            if(col[v=edge[i].to]==col[cr])
                {flag=1;return;}
            else if(!col[v])col[v]=(col[cr]^1),dfs(v);
            if(flag)return;
        }
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        init();
        for(int i=1;i<=n;i++) if(!col[i])
        {
            col[i]=2;dfs(i);if(flag)break;
        }
        if(flag){
            printf("0");return 0;
        }
        now=1;
        for(int i=1;i<=n;i++)
        {
            ps[a[i]]=col[i];
            if(col[i]==2)printf("a ");
            else printf("c ");
            while(ps[now]){
                if(ps[now++]==2)printf("b ");
                else printf("d ");
            }
        }
        return 0;
    }
    View Code

    从代码的col和ps可以看出二分图染色和最后的模拟有一定程度的重复。其实可以大胆地直接模拟就行了。

    (此方法源自洛谷用户cmd2001。在洛谷题解的第2页可以看到。)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N=1005;
    int n,r[N],ct,now,a[N],ta,b[N],tb,tot;
    char ch[N<<1];
    bool flag;
    bool check(int cr)
    {
        int i;
        for(i=cr+1;i<=n;i++)if(r[i]>r[cr]&&r[i]>b[tb])break;
        for(int j=i+1;j<=n;j++)if(r[j]<r[cr])return 0;
        return 1;
    }
    int main()
    {
        scanf("%d",&n);int lm=(n<<1);now=1;ct=1;
        for(int i=1;i<=n;i++)scanf("%d",&r[i]);
        a[0]=b[0]=n+1;
        for(int i=1;i<=lm;i++)
        {
            if(a[ta]==now)
            {
                ch[++tot]='b';ta--;now++;
                continue;
            }
            if(b[tb]==now)
            {
                ch[++tot]='d';tb--;now++;
                continue;
            }
            if(ct<=n&&r[ct]<a[ta]&&check(ct))
            {
                a[++ta]=r[ct++];ch[++tot]='a';
                continue;
            }
            if(ct<=n&&r[ct]<b[tb])
            {
                b[++tb]=r[ct++];ch[++tot]='c';
                continue;
            }
            flag=1;break;
        }
        if(flag)printf("0");
        else for(int i=1;i<=lm;i++)printf("%c ",ch[i]);
        return 0;
    }
    View Code

    这道题教会我们要好好分析性质。别只分析出一个浅显的了!

  • 相关阅读:
    应用Solaris11放置光盘修复solaris引导妨碍
    HP 3803TX 装置debian4 Linux
    释放linux细碎的内存
    linux批量查找文件内容
    Oracle 10g R2 for Solaris x86在Solaris 11上的装配
    Linux 零碎进修之shell剧本进修
    华硕易PC台式机版7月环球上市 或运转Linux
    Linux文件琐细 一分钱一分货
    linux下平安管理
    预装Windows或Ubuntu,戴尔出Mini Inspiron 8.9寸笔记本
  • 原文地址:https://www.cnblogs.com/Narh/p/9213825.html
Copyright © 2020-2023  润新知