ACM/ICPC 之 双向链表_构造列表-模拟祖玛 (TSH OJ-Zuma(祖玛))
这一题是TsingHua OJ上的一道题目,学堂在线的一位数据结构老师的题目(原创),所以我直接把题目先贴下来了,这道题对复习双向链表很有帮助,而且也对数据结构中List,也就是对列表的回顾也是很有帮助的。
祖玛(Zuma)
描述
祖玛是一款曾经风靡全球的游戏,其玩法是:在一条轨道上初始排列着若干个彩色珠子,其中任意三个相邻的珠子不会完全同色。此后,你可以发射珠子到轨 道上并加入原有序列中。一旦有三个或更多同色的珠子变成相邻,它们就会立即消失。这类消除现象可能会连锁式发生,其间你将暂时不能发射珠子。
开发商最近准备为玩家写一个游戏过程的回放工具。他们已经在游戏内完成了过程记录的功能,而回放功能的实现则委托你来完成。
游戏过程的记录中,首先是轨道上初始的珠子序列,然后是玩家接下来所做的一系列操作。你的任务是,在各次操作之后及时计算出新的珠子序列。
输入
第一行是一个由大写字母'A'~'Z'组成的字符串,表示轨道上初始的珠子序列,不同的字母表示不同的颜色。
第二行是一个数字n,表示整个回放过程共有n次操作。
接下来的n行依次对应于各次操作。每次操作由一个数字k和一个大写字母Σ描述,以空格分隔。其中,Σ为新珠子的颜色。若插入前共有m颗珠子,则k ∈ [0, m]表示新珠子嵌入之后(尚未发生消除之前)在轨道上的位序。
输出
输出共n行,依次给出各次操作(及可能随即发生的消除现象)之后轨道上的珠子序列。
如果轨道上已没有珠子,则以“-”表示。
Example
Input
ACCBA
5
1 B
0 A
2 B
4 C
0 A
Output
ABCCBA
AABCCBA
AABBCCBA
-
A
限制
0 ≤ n ≤ 10^4
0 ≤ 初始珠子数量 ≤ 10^4
时间:2 sec
内存:256 MB
解题思路:
这道题考察的就是大家对列表的理解和DIY重构能力,模拟Zuma这一远近闻名的游戏中的色块序列。
我们来回顾一下数据结构的两个基本结构 向量(vetor)和列表(List),这两个数据结构非常类似,但是两种结构的优势和构造却也有很大差距,Vetor实质就是一个可以动态增长空间的数组,也就是通俗的动态数组,可以方便得对数据进行动态管理。
但是Vetor相对于List却让人觉得有些静态了,因为List的实质是一个双向链表,因此可以比Vetor更加高效得insert或者delete数据,但是List不能随意查询到其中的数据,需要通过指针一次次得遍历查找,即便可以从首部或者尾部查找,但总得来说,每一次遍历的时间度依然是O(n)。
Ps:另外有一个特别注意的地方,当数据量比较大的时候,每次输出都会调用一次I/O接口(即printf OR cout),这样会造成大量调用,如果按照最坏情况,最大数组有20000个字符,最大输出有10000次,因此调用量可能会达到10^8次,如此大的调用量显然会在数据极端的时候爆出TLE,因此我们也应该对I/O调用的次数也要优化,我这里直接用一个非常大的数组存储所有情况,直到最后输出。
如果没有这个优化,在TsingHhua OJ上只能通过95%的数据,最后一个测试用例是过不了的。
Ps:然后注意数据中输入序列可以为空。(length==0的情况刚开始一直没注意,所以第二个测试用例一直过不了。。。ヾ(。`Д´。),做这道题就因为这个耗时一小时啊!!)
所以注意输入数据的时候用gets()之类读取行字符的函数。
Ok,贴Code!
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 6 #define MAX 200000000 7 8 /*祖玛色块类*/ 9 struct Zuma{ 10 char date; 11 Zuma *up; 12 Zuma *down; 13 Zuma(){}; 14 Zuma(char s):date(s){}; 15 }*header,*tailer; //首尾哨兵 16 17 char s[MAX]; 18 int length; //链表长度 19 int k; //记录数据长度 20 21 /*双向链表-尾插法*/ 22 void Creat_zuma(char *s) 23 { 24 header = new Zuma(); 25 header->up = NULL; 26 27 Zuma *rear = header; //定义尾部指针-穿针 28 for (int i = 0; i < length; i++) 29 { 30 Zuma *p = new Zuma(s[i]); 31 rear->down = p; 32 p->up = rear; 33 34 rear = p; //换针 35 } 36 tailer = new Zuma(); 37 rear->down = tailer; 38 tailer->up = rear; 39 tailer->down = NULL; 40 } 41 42 /*遍历查找pos位置的指针*/ 43 Zuma* Find(int pos) 44 { 45 int counter = 0; 46 Zuma *p = header; 47 if (length - pos >= pos) //首部遍历 48 { 49 while (counter < pos && p->down != tailer) 50 { 51 p = p->down; 52 counter++; 53 } 54 } 55 else{ //尾部遍历 56 p = tailer; 57 counter = length; 58 while (counter >= pos && p->up != header) 59 { 60 p = p->up; 61 counter--; 62 } 63 } 64 return p; 65 } 66 67 /*消除*/ 68 Zuma* Remove(Zuma *cur,char c) 69 { 70 while (1) 71 { 72 Zuma *pre = cur->down; 73 int counter = 0; 74 while (cur != header && cur->date == c) //向前查重 75 { 76 cur = cur->up; 77 counter++; 78 } 79 while (pre != tailer && pre->date == c) //向后查重 80 { 81 pre = pre->down; 82 counter++; 83 } 84 if (counter >= 3) //重复元素大于三个 85 { 86 length -= counter; 87 Zuma *p1 = cur->down, *p2; 88 while (p1 != pre) //delete 89 { 90 p2 = p1->down; 91 delete p1; 92 p1 = p2; 93 } 94 cur->down = pre; 95 if (pre != NULL) 96 pre->up = cur; 97 c = cur->date; 98 } 99 else break; 100 } 101 return cur; 102 } 103 104 /*插入*/ 105 void Insert(Zuma *p, char c) 106 { 107 Zuma *x = new Zuma(c); 108 if (p->down != NULL) 109 { 110 x->up = p; 111 x->down = p->down; 112 p->down->up = x; 113 p->down = x; 114 } 115 else{ 116 x->up = p; 117 x->down = NULL; 118 p->down = x; 119 } 120 length++; 121 } 122 int main() 123 { 124 int n; 125 gets(s); 126 scanf("%d", &n); 127 length = strlen(s); 128 /*搭建*/ 129 Creat_zuma(s); 130 131 for (int t = 0; t < n; t++) 132 { 133 char c[2]; 134 int pos; 135 scanf("%d%s", &pos, &c); 136 137 Zuma *p = Find(pos); 138 Insert(p, c[0]); 139 Zuma *flag = Remove(p, c[0]); 140 /*Record*/ 141 if (flag == header && flag->down == tailer) 142 { 143 s[k++] = '-'; 144 s[k++] = '\n'; 145 } 146 else{ 147 flag = header; 148 while (flag->down != tailer) 149 { 150 s[k++] = flag->down->date; 151 flag = flag->down; 152 } 153 s[k++] = '\n'; 154 } 155 /*Single Input*/ 156 if (t == n - 1) 157 { 158 s[k] = '\0'; 159 printf("%s", s); 160 k = 0; 161 } 162 } 163 return 0; 164 }