hdu 5818 Joint Stacks 2016 Multi-University 7
2016-08-10 17:53
351 查看
Problem:acm.hdu.edu.cn/showproblem.php?pid=5818
官方题解:bestcoder.hdu.edu.cn/blog/2016-multi-university-training-contest-7-solutions-by-sysu/
题意:两个栈,支持push、pop、merge 3种操作
push x y :把 y 压入栈 x
pop x :栈 x 弹出一个元素,输出它的值
merge x y :把 y 中的元素全部移到 x 中,并且保持所有元素的进栈时的先后顺序
分析:官方题解中有种解法,是开第3个栈,当要合并的时候把两个栈里的元素全部放到这个栈里,并且清空原来两个栈
我理解:
要合并时,比如 merge A B,就把 b 栈的标记指针打到 a 栈的栈顶指针那,表示此标记开始以下的元素都属于 b 栈
同时把 a 栈在 b 栈上的标记指针打到 b 栈的栈底
那么属于 a 栈的元素就包括:a 栈中从栈顶指针 topa 到 b 的标记指针 markb 中间一段的元素,和 b 栈中从 a 栈的标记指针 marka 到 b 栈栈底一段的元素
要弹栈时,比如 pop B,就要比较 topb 所指元素(如果有)与 markb 所指元素(如果有)的进栈顺序,输出较新的一个,并且删掉那个元素
用双向链表实现栈(因为删元素的时候要把与它相邻的两个元素连起来)
注意:如果 pop B 的时候要删的是 markb 所指的元素,而 topa == markb,那么在删元素前更改 markb 的指向时,要把 topa 也一同改了(不然 topa 成野指针)
官方题解:bestcoder.hdu.edu.cn/blog/2016-multi-university-training-contest-7-solutions-by-sysu/
题意:两个栈,支持push、pop、merge 3种操作
push x y :把 y 压入栈 x
pop x :栈 x 弹出一个元素,输出它的值
merge x y :把 y 中的元素全部移到 x 中,并且保持所有元素的进栈时的先后顺序
分析:官方题解中有种解法,是开第3个栈,当要合并的时候把两个栈里的元素全部放到这个栈里,并且清空原来两个栈
我理解:
#include <stdio.h> #define N 100000 struct { int v; int id; // 标明元素的进栈先后 } a , b , c ; // 3个栈 int main() { int n,kase=1; while( ~scanf("%d%*c",&n) && n ) { printf("Case #%d:\n",kase++); // 3个栈的栈顶指针 int topa = 0, topb = 0, topc = 0; // “时间”标明元素进栈先后 int time; // own标记c中的元素属于A还是B char own = '\0'; for(time=0; time<n; time++) { char op[7],who; int val,i,j; scanf("%s %c%*c",op, &who); if( op[1] == 'u' ) // push { scanf("%d%*c", &val); if( who == 'A' ) { a[topa].v = val; a[topa++].id = time; } else { b[topb].v = val; b[topb++].id = time; } } else if( op[1] == 'o' ) // pop { if( who == 'A' ) { if( topa ) 4000 // 如果a栈中有元素,必是最新的 printf("%d\n", a[--topa].v); else if( topc && own == 'A' ) // c中有元素且属于A printf("%d\n", c[--topc].v); } else { if( topb ) printf("%d\n", b[--topb].v); else if( topc && own == 'B' ) printf("%d\n", c[--topc].v); } } else // merge { // 读掉第2个参数 scanf("%*s"); // 把a、b栈的元素都放进c栈 for(i=j=0; i<topa || j<topb; ) if( i<topa && j<topb ) //a、b栈都非空 { if( a[i].id < b[j].id ) // 比较入栈顺序 { c[topc].v = a[i].v; c[topc++].id = a[i++].id; } else { c[topc].v = b[j].v; c[topc++].id = b[j++].id; } } else if( i<topa ) // a栈非空 { c[topc].v = a[i].v; c[topc++].id = a[i++].id; } else // b栈非空 { c[topc].v = b[j].v; c[topc++].id = b[j++].id; } // 清空a、b栈 topa = topb = 0; // 第1个参数表示归属 own = who; } } } return 0; }可以开两个栈,记录两个栈的栈顶指针(topa,topb)和各自的一个标记指针(marka,markb)
要合并时,比如 merge A B,就把 b 栈的标记指针打到 a 栈的栈顶指针那,表示此标记开始以下的元素都属于 b 栈
同时把 a 栈在 b 栈上的标记指针打到 b 栈的栈底
那么属于 a 栈的元素就包括:a 栈中从栈顶指针 topa 到 b 的标记指针 markb 中间一段的元素,和 b 栈中从 a 栈的标记指针 marka 到 b 栈栈底一段的元素
要弹栈时,比如 pop B,就要比较 topb 所指元素(如果有)与 markb 所指元素(如果有)的进栈顺序,输出较新的一个,并且删掉那个元素
用双向链表实现栈(因为删元素的时候要把与它相邻的两个元素连起来)
注意:如果 pop B 的时候要删的是 markb 所指的元素,而 topa == markb,那么在删元素前更改 markb 的指向时,要把 topa 也一同改了(不然 topa 成野指针)
#include <stdio.h> #include <stdlib.h> typedef struct Node { int v,id; struct Node *pre,*next; // 上面和下面 }node; void push(node **s, int val, int tm) { node *p = malloc( sizeof( node ) ); p->v = val; p->id = tm; p->pre = NULL; p->next = *s; if(*s) (*s)->pre = p; *s = p; } /* 删除元素 */ void erase(node **me, node **histop) { node *q = *me; printf("%d\n", q->v); if( q->pre ) q->pre->next = q->next; if( q->next ) q->next->pre = q->pre; *me = q->next; if( *histop == q ) *histop = *me; free(q); } void pop(node **mytop, node **mymark, node **histop, node *hismark) { // 我栈中有属于我的元素,他栈中没有 if( *mytop != hismark && !*mymark ) erase(mytop,histop); // 我栈没有,他栈有 else if( *mytop == hismark && *mymark ) erase(mymark,histop); // 我有他有 else if( *mytop != hismark && *mymark ) if( (*mytop)->id < (*mymark)->id ) erase(mymark,histop); else erase(mytop,histop); } void merge(node **mymark, node **hismark, node *histop) { // 标记打到对方栈顶 *mymark = histop; // 对方的标记打到“栈底” *hismark = NULL; } /* 销毁链表 */ void destroy(node *s) { while(s) { node *q = s; s = s->next; free(q); } } int main() { int n,kase=1; while( ~scanf("%d%*c",&n) && n ) { int i; // 栈顶指针,标记指针 node *topa,*topb,*marka,*markb; printf("Case #%d:\n", kase++); topa = topb = marka = markb = NULL; for(i=0; i<n; i++) { char op[7],who; int val; scanf("%s %c%*c", op, &who); if( op[1] == 'u' ) { scanf("%d%*c", &val); if( who == 'A' ) push(&topa, val, i); else push(&topb, val, i); } else if( op[1] == 'o' ) { if( who == 'A' ) pop(&topa, &marka, &topb, markb); else pop(&topb, &markb, &topa, marka); } else { scanf("%*s"); if( who == 'A' ) merge(&marka, &markb, topb); else merge(&markb, &marka, topa); } } // 销毁链表 destroy(topa); destroy(topb); } return 0; }本来想用C++的 vertor 来写栈,删元素时直接用它的 erase(),然而wa了…不知道它删完一个元素后,是不是后面元素的下标都自动 -1 还是怎么变,还是因为写漏了个冒号…
相关文章推荐
- (HDU 5818)2016 Multi-University Training Contest 7 Joint Stacks (模拟、stack)
- hdu 5818 2016 Multi-University Training Contest 7(模拟)
- 数据结构 ( 优先队列&&栈 )——HDU 5818 ( 2016 Multi-University Training Contest 7 1010 )
- 2016 Multi-University Training Contest 4 hdu 5775 Bubble Sort【树状数组+思维】
- 最长递增子序列 ( LIS )——The All-purpose Zero ( HDU 5773 ) ( 2016 Multi-University Training Contest 4 1010 )
- hdu 5861Road(2016 Multi-University Training Contest 10——线段树+扫描线)
- 2016 Multi-University Training Contest 1 1004 hdu 5726 二分+RMQ
- hdu 5802 Windows 10(2016 Multi-University Training Contest 6——贪心+dfs)
- hdu 5734 (2016 Multi-University Training Contest 2)
- 欧拉定理——PowMod ( HDU 5728 )(2016 Multi-University Training Contest 1 1006)
- HDU 5810 Balls and Boxes(打表找规律)——2016 Multi-University Training Contest 7 1002
- hdu 5831 Rikka with Parenthesis II 2016 Multi-University 8
- hdu 5867 Water problem(2016 Multi-University Training Contest 10——水题)
- HDU 5785 Interesting 2016 Multi-University Training Contest 5(Manacher)
- hdu 5793 2016 Multi-University Training Contest 6(快速幂+乘法逆元)
- 2016 Multi-University Training Contest 1-1001---HDU 5723 Abandoned country(DFS+最小生成树)
- (HDU 5802)2016 Multi-University Training Contest 6 Windows 10 (贪心)
- (HDU 5723)2016 Multi-University Training Contest 1 Abandoned country(图论)
- HDU 5735 Born Slippy ( from:2016 Multi-University Training Contest 2 )
- (HDU 5726)2016 Multi-University Training Contest 1 GCD(数学)