题目链接:https://vjudge.net/problem/UVA-12657
题解:这一题的题意是有一行从1到n编号的盒子,按给定的4种指令对盒子进行操作,最后输出奇数位置上的盒子编号的和。解题的数据结构选择双向链表,增加头尾指针用作标注,另外使用一个pos数组记录每个盒子的指针位置,方便直接取得盒子指针。最后根据题意按指令对盒子进行模拟操作。我在这一题中使用的是自己写的指针链表,对指针之间的指向掌握要求比较高。LRJ书中同样给的是数组模拟双向链表,值得参考,也是需要我学习的。
感受:其实解这一题花了我不少的时间的,最开始的时候写出来了一份代码,也是可以解决给定样例的,但是其他例子上有的会有错误,这个错误我检查了好久,后来把之前的写的代码删除重新解题,换了一种结构之后仍然会有同样的问题。我仔细读题之后发现,我对题目的一点理解有误,即ingore this if X is already the left of Y。发现了这个问题之后,直接就AC了。这说明了仔细读懂题目的重要性,每一个细节都得注意到,不然设计和程序就会有很大的问题。另外,在重写的过程中,我意识到了抽象的重要性,在对题目理解加深的基础之后,会将自己的思维融入到解题过程中,这样代码将会变得简短、凝练,但是其他人阅读便需要动一些脑筋了,这也是为什么我读LRJ书中的代码会很困难,感觉他的那些代码都经过了高度的抽象,这是需要我学习的点。
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
const int maxn = 1e5 + 10;
struct Num {
int num;
Num *pre = NULL;
Num *next = NULL;
};
Num *pos[maxn];
void create(int n) {
Num *head = new Num();
pos[0] = head;
for (int i = 1; i <= n+1; i++)
{
Num *newNum = new Num();
if (i < n + 1) {
newNum->num = i;
}
else {
newNum->num = 0;
}
head->next = newNum;
newNum->pre = head;
head = newNum;
pos[i] = head;
}
}
void swap_Num(Num *P,Num *Q) {
if (P->next == Q||P->pre==Q) {
if (P->pre == Q) {
Num *t = P;
P = Q;
Q = t;
}
P->pre->next = Q;
Q->pre = P->pre;
P->next = Q->next;
Q->next->pre = P;
P->pre = Q;
Q->next = P;
}
else {
Num *t1 = Q->pre;
Num *t2 = Q->next;
P->pre->next = Q;
Q->pre = P->pre;
Q->next = P->next;
P->next->pre = Q;
P->pre = t1;
t1->next = P;
P->next = t2;
t2->pre = P;
}
}
void insert_Num(Num *p, Num *q,int flag) {
if (!flag) {
p->pre->next = p->next;
p->next->pre = p->pre;
q->pre->next = p;
p->pre = q->pre;
p->next = q;
q->pre = p;
}
else {
p->next->pre = p->pre;
p->pre->next = p->next;
q->next->pre = p;
p->next = q->next;
p->pre = q;
q->next = p;
}
}
int main() {
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
int m, n;
int c = 0;
while (cin >> n >> m) {
//cout << n << " " << m << endl;
memset(pos, NULL, sizeof(pos));
//create a list of 1...N
create(n);
Num *head = pos[0];
Num *endP = pos[n+1];
int tp = 0;
long long int s = 0;
int flag = 0;
for (int i = 0; i < m; i++)
{
int type = 0, X = 0, Y = 0;
cin >> type;
if (type != 4) {
cin >> X >> Y;
}
Num *temp = NULL;
switch (type)
{
case 1:
if (!flag) {
if (pos[X]->next == pos[Y])continue;
}
else {
if (pos[X]->pre == pos[Y])continue;
}
if(pos[X]->next==pos[Y]||pos[X]->pre==pos[Y])
swap_Num(pos[X], pos[Y]);
else{
insert_Num(pos[X], pos[Y],flag);
}
break;
case 2:
if (!flag) {
if (pos[X]->pre == pos[Y])continue;
}
else {
if (pos[X]->next == pos[Y])continue;
}
if (pos[X]->next == pos[Y] || pos[X]->pre == pos[Y])
swap_Num(pos[X], pos[Y]);
else {
if (!flag) {
insert_Num(pos[X], pos[Y]->next,flag);
}
else {
insert_Num(pos[X], pos[Y]->pre,flag);
}
}
break;
case 3:
swap_Num(pos[X],pos[Y]);
break;
case 4:
if (flag) {
flag = 0;
}
else {
flag = 1;
}
temp = head;
head = endP;
endP = temp;
break;
default:
break;
}
}
s = 0;
tp = 0;
if (!flag)
{
for (Num *it = head->next; it->next != NULL; it = it->next,tp++)
{
if (tp % 2 == 0) {
s += it->num;
}
}
}
else {
for (Num *it = head->pre; it->pre != NULL; it = it->pre, tp++)
{
if (tp % 2 == 0) {
s += it->num;
}
}
}
cout << "Case " << ++c << ": " << s << endl;
for (int i = 1; i <= n + 1; i++)delete pos[i];
}
return 0;
}