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

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

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

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

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

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

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

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

然后发现只有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=;
int n,a[N],head[N],xnt,col[N],ps[N],now,f[N];
bool flag;
struct Edge{
int next,to;
Edge(int n=,int t=):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+;
for(int i=n-;i;i--)
{
f[i]=min(f[i+],a[i+]);
for(int j=i+;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=;return;}
else if(!col[v])col[v]=(col[cr]^),dfs(v);
if(flag)return;
}
}
int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++)scanf("%d",&a[i]);
init();
for(int i=;i<=n;i++) if(!col[i])
{
col[i]=;dfs(i);if(flag)break;
}
if(flag){
printf("");return ;
}
now=;
for(int i=;i<=n;i++)
{
ps[a[i]]=col[i];
if(col[i]==)printf("a ");
else printf("c ");
while(ps[now]){
if(ps[now++]==)printf("b ");
else printf("d ");
}
}
return ;
}

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

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

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

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

洛谷 1155 (NOIp2008)双栈排序——仔细分析不合法的条件的更多相关文章

  1. Luogu1155 NOIP2008 双栈排序 【二分图染色】【模拟】

    Luogu1155 NOIP2008 双栈排序 题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过 2个栈 S1 和 S2 ,Tom希望借助以下 44 种操作实现将输入序列升序排序. 操作 ...

  2. NOIP2008双栈排序[二分图染色|栈|DP]

    题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1 ...

  3. noip2008 双栈排序

    题目描述 Description \(Tom\)最近在研究一个有趣的排序问题.如图所示,通过\(2\)个栈\(S_1\)和\(S_2\),\(Tom\)希望借助以下\(4\)种操作实现将输入序列升序排 ...

  4. Noip2008双栈排序

    [问题描述] 用两个栈使一个1...n的排列变得有序.一共有四个操作: A.stack1.push() 读入一个放入栈一 B.stack1.pop() 弹出栈一放入输出序列 C.stack2.push ...

  5. NOIP2008双栈排序(贪心)

    题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1 ...

  6. [题解] [NOIP2008] 双栈排序——关系的冲突至图论解法

    Problem 题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操 ...

  7. [NOIP2008]双栈排序 【二分图 + 模拟】

    题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1 ...

  8. [luogu1155 NOIP2008] 双栈排序 (二分图染色)

    传送门 Description Input 第一行是一个整数 n . 第二行有 n 个用空格隔开的正整数,构成一个 1−n 的排列. Output 共一行,如果输入的排列不是"可双栈排序排列 ...

  9. $[NOIp2008]$双栈排序 栈/二分图/贪心

    \(Sol\) 先考虑单栈排序,怎么样的序列可以单栈排序呢?设\(a_i\)表示位置\(i\)是哪个数.\(\exist i<j<k\),都没有\(a_k<a_i<a_j\), ...

随机推荐

  1. 并发-HashMap和HashTable源码分析

    HashMap和HashTable源码分析 参考: https://blog.csdn.net/luanlouis/article/details/41576373 http://www.cnblog ...

  2. lastIndexOf 方法 (Array) (JavaScript)

    lastIndexOf 方法 (Array) (JavaScript) 返回指定的值在数组中的最后一个匹配项的索引. 语法         array1.lastIndexOf(searchEleme ...

  3. Jar 包 及运行Jar包 - 转载

    Eclipse的jar file和Runnable JAR file的区别 - 及bat运行Runnable JAR文件 1.两种jar的区别 jar file是最普通的jar包,即平时我们工程中li ...

  4. TWX 比较好的多线程使用实例

    using Newtonsoft.Json;using System;using System.Collections.Generic;using System.Configuration;using ...

  5. 机器学习三剑客之Pandas

      pandas Pandas是基于Numpy开发出的,专门用于数据分析的开源Python库 Pandas的两大核心数据结构 Series(一维数据)   Series   创建Series的方法   ...

  6. Minhash 算法 及其应用

    背景: 我遇到一个问题,要计算140万商品的杰卡德相似度.如果直接要直接两两计算的话,这计算量根本算不了,而且也没必要. 分析: 在这些商品中很多商品的相似度并不高,也就是说其中达到相似度阈值的商品只 ...

  7. js 小复习1

    1.数组 增删改查 , , , , ]; // arr.push(18); // 添加数组后面 更改长度 // arr.unshift(12); // 添加数组前面 // arr.pop(); // ...

  8. koa2使用&&中间件&&angular2的koa托管

    文章导航 1,koa2使用: 2,写中间件: 3,koa2路由配置angular2; 一.先上代码,一篇,看完koa2中大多基础方法: const Koa=require('koa'); const ...

  9. Selenium with Python 003 - 页面元素定位

    WebUI自动化,首先需要定位页面中待操作的元素,然后进行各种事件操作,这里我们首先介绍Selenium Python 如何定位页面元素,WebDriver 提供了一系列的方法. 定位单个页面元素(返 ...

  10. 【mysql 】sql删除重复记录 You can't specify target table '表名' for update in FROM clause

    用下面的语句就报语法出错: delete from tab_record where recordid not in (select  min(c.recordid) as recordid from ...