题目: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. JAVA基础补漏--多态

    Fu obj = new ZI(); 访问成员变量规则 编译看左,运行看左. obj.num; 1.直接通过对象名访问成员变量:看等号左右是谁,优先用谁,没有则往上找. obj.getnum(); 2 ...

  2. tar 解压命令学习与总结

    tar -c: 建立压缩档案 -x:解压 -t:查看内容 -r:向压缩归档文件末尾追加文件 -u:更新原压缩包中的文件 这五个是独立的命令,压缩解压都要用到其中一个,可以和别的命令连用但只能用其中一个 ...

  3. LeetCode——Find the Difference

    LeetCode--Find the Difference Question Given two strings s and t which consist of only lowercase let ...

  4. 记录使用Buildbot遇到的坑

    Buildbot Tips Buildbot也是个大坑..我并不熟悉python,偏偏文档又少.这几天使用buildbot出了不少坑.有的解决了,有的绕过去,这里都把它们一一记下来. Force Bu ...

  5. Pandas分组(GroupBy)

    任何分组(groupby)操作都涉及原始对象的以下操作之一.它们是 - 分割对象 应用一个函数 结合的结果 在许多情况下,我们将数据分成多个集合,并在每个子集上应用一些函数.在应用函数中,可以执行以下 ...

  6. CNI:容器网络接口

    CNI 简介 不管是 docker 还是 kubernetes,在网络方面目前都没有一个完美的.终极的.普适性的解决方案,不同的用户和企业因为各种原因会使用不同的网络方案.目前存在网络方案 flann ...

  7. 【Python】词典

    词典 (dictionary).与列表相似,词典也可以储存多个元素.这种储存多个元素的对象称为容器(container) 基本概念 常见的创建词典的方法: >>>dic = {'to ...

  8. EL表达式 分割字符串 ,forEach定次循环

    后台取出来的是字符串  以 a,b,c,   的形式  前台要将字符串中的“,”去掉 ,并forEach重新拼接 list.labelsName不用加${} <c:set value=" ...

  9. 【sparkStreaming】kafka作为数据源的生产和消费

    1.建立生产者发送数据 (1)配置zookeeper属性信息props (2)通过 new KafkaProducer[KeyType,ValueType](props) 建立producer (3) ...

  10. 【lightoj-1055】Going Together(BFS)

    链接:http://www.lightoj.com/volume_showproblem.php?problem=1055 类似推箱子的游戏,一条命令可以让abc三个小人同时移动,但是出界或者撞墙是不 ...