题目: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. poj2349 Arctic Network - 最小生成树

    2017-08-04 16:19:13 writer:pprp 题意如下: Description The Department of National Defence (DND) wishes to ...

  2. C++ 函数后面的const

    一个函数 AcGePoint3dstartPoint() const; const放在后面跟前面有区别么 ==> 准确的说const是修饰this指向的对象的 譬如,我们定义了 classA{ ...

  3. JavaScript 兼容各大浏览器阻止冒泡事件

    JavaScript 兼容各大浏览器阻止冒泡事件 function stopEvent(event) { //阻止冒泡事件 //取消事件冒泡 var e = arguments.callee.call ...

  4. 公共域名服务DNS 114.114.114.114和8.8.8.8

    一.两者的联系 114.114.114.114和8.8.8.8,这两个IP地址都属于公共域名解析服务DNS其中的一部分,而且由于不是用于商业用途的,这两个DNS都很纯净,不用担心因ISP运营商导致的D ...

  5. python之list,tuple,str,dic简单记录(二)

    切片对象:例子:In [13]: l = [1,23,4,5,5,6,8]In [14]: l[::1]Out[14]: [1, 23, 4, 5, 5, 6, 8] In [15]: l[::2]O ...

  6. javascript简单介绍总结(一)

    DOM (Document Object Model)(文档对象模型)是用于访问 HTML 元素的正式 W3C 标准.在 HTML 中,JavaScript 语句向浏览器发出的命令.语句是用分号分隔: ...

  7. Build_Release.bat

    Build_Release.bat @echo off pushd "%~dp0" set tag=Release set PATH="C:\Program Files ...

  8. 第七届蓝桥杯C-B-10-最大比例/gcd变形

    最大比例 X星球的某个大奖赛设了M级奖励.每个级别的奖金是一个正整数.并且,相邻的两个级别间的比例是个固定值.也就是说:所有级别的奖金数构成了一个等比数列.比如:16,24,36,54其等比值为:3/ ...

  9. 【spark】连接Hbase

    0.我们有这样一个表,表名为Student 1.在Hbase中创建一个表 表明为student,列族为info 2.插入数据 我们这里采用put来插入数据 格式如下   put  ‘表命’,‘行键’, ...

  10. Linux下用c语言实现whereis.

    简单的一个whereis的实现,代码如下: #include <stdio.h> #include <errno.h> #include <dirent.h> #i ...