luoguP1155 双栈排序
来源:互联网 发布:linux卸载snmp服务 编辑:程序博客网 时间:2024/06/03 10:38
题目描述
Tom最近在研究一个有趣的排序问题。如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序。
操作a
如果输入序列不为空,将第一个元素压入栈S1
操作b
如果栈S1不为空,将S1栈顶元素弹出至输出序列
操作c
如果输入序列不为空,将第一个元素压入栈S2
操作d
如果栈S2不为空,将S2栈顶元素弹出至输出序列
输入输出格式
输入格式:
输入文件twostack.in的第一行是一个整数n。
第二行有n个用空格隔开的正整数,构成一个1~n的排列。
输出格式:
输出文件twostack.out共一行,如果输入的排列不是“可双栈排序排列”,输出数字0;否则输出字典序最小的操作序列,每两个操作之间用空格隔开,行尾没有空格。
输入输出样例
输入样例#1:
【输入样例1】
4
1 3 2 4
【输入样例2】
4
2 3 4 1
【输入样例3】
3
2 3 1
输出样例#1:
【输出样例1】
a b a a b b a b
【输出样例2】
0
【输出样例3】
a c a b b d
说明
30%的数据满足: n<=10
50%的数据满足: n<=50
100%的数据满足: n<=1000
分析:
第一眼看过去,很简单啊,模拟一下就好了
只要遵循:
在栈里的元素一定是单调递减的
栈里相邻元素相差的越少越好,
优先选择第一个栈
实测:40分
这完全就是钻制度的空子。。。
好吧,说正经的
考虑a[i],a[j]两个元素不能进入同一个栈的条件.
注意,这里所说的”a[i],a[j]两个元素不能进入同一个栈“,
是自始至终不能进入一个栈,
即如果有解,那么a[i],a[j]一定进入过的栈不同.
条件:存在k使得i < j < k且a[k] < a[i] < a[j]
进栈顺序i->j->k
栈中的元素一定是单调减的
如果ta们在一个栈中,那么进栈顺序是j->i->k,与原命题矛盾
那知道了这个有什么用呢
我们可以知道元素两两能不能在一起,
如果i和j不能在一起,j和k不能在一起,i和k不能在一起,那原序列无解
我们把不能在一起的一对点之间连边
(突然觉得这蜜汁像关押罪犯,当有冲突时,就把边两端的点分配到不同的集合中去)
之后遍历一遍进行01染色
这样我们知道了进栈的状况,就可以直接模拟输出了
(直接上40分的骗分)
tip
按理说在处理冲突点对的时候是O(n^3)的复杂度,对于1000太大了,大神说要用dp优化一下,但是luogu数据实在是太耿直了,打的三方暴力就这样A了
简单说一下dp优化,
因为我们只要找到一个k满足就判定是冲突点对,
所以设f[i]表示i-n中的最小值
如果最小值都满足不了那就不可能了
这样可以把k的循环降到O(1)
这里写代码片#include<cstdio>#include<cstring>#include<iostream>#include<queue>using namespace std;const int N=1010;int n,a[N];char s[N];struct node{ int x,y,nxt;};node way[N<<1];int st[N],tot=0,co[N],st1[N],st2[N];void add(int u,int w){ tot++; way[tot].x=u;way[tot].y=w;way[tot].nxt=st[u];st[u]=tot; tot++; way[tot].x=w;way[tot].y=u;way[tot].nxt=st[w];st[w]=tot;}void doit(){ int i,j; memset(co,-1,sizeof(co)); queue<int> q; q.push(way[1].x); co[way[1].x]=0; while (!q.empty()) //染色 { int r=q.front(); q.pop(); for (i=st[r];i;i=way[i].nxt) { if (co[way[i].y]==-1) { co[way[i].y]=(co[r]==0 ? 1:0); q.push(way[i].y); } else if (co[way[i].y]==co[r]) { printf("0\n"); return; } } } int t=-1,t1=0,t2=0,k=1; for (i=1;i<=n;i++) { if (a[k]==i) { printf("a b ");k++; continue; } if (st1[t1]==i) { printf("b "); t1--; continue; } if (st2[t2]==i) { printf("d "); t2--; continue; } while (a[k]!=i) { if (co[k]==0||co[k]==-1) printf("a "),st1[++t1]=a[k]; else printf("c "),st2[++t2]=a[k]; k++; } printf("a b ");k++; } return; }int main(){ scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&a[i]); for (int i=1;i<n-1;i++) //i<j<k a[k]>a[i]>a[j] for (int j=i+1;j<n;j++) { if (a[i]<a[j]) for (int k=j+1;k<=n;k++) if (a[k]<a[i]) { add(i,j);break; } } doit(); return 0;}
- luoguP1155 双栈排序
- [NOIP2008]双栈排序
- NOIP2008 双栈排序
- sicily双栈排序
- 双栈排序
- [noip2008]双栈排序
- 双栈排序
- Codevs1170 双栈排序
- 双栈排序
- 双栈排序
- 双栈排序
- 双栈排序
- 双栈排序
- 双栈排序
- 双栈排序
- P1155 双栈排序
- 1002. 双栈排序
- 双栈排序
- linux查询日志
- 百度编辑器(UEditor)自定义工具栏
- maven scope含义的说明
- SVN报错Warning: post-commit hook failed (exit code 1) with output:
- 51nod 1240 莫比乌斯函数
- luoguP1155 双栈排序
- Windows Socket和Linux Socket编程的区别
- 「网络流 24 题」试题库
- [DL_BOOK]深度学习 第六章 深度前向网络 [part1]
- c语言 传递结构指针案例
- Java集合List、Set、Map的遍历方法
- 数据库事务
- Day6-15.Syntax
- 有关音频编码的知识与技术参数,常用音频协议介绍