双向链表 Boxes in a Line UVA - 12657

Posted 子狼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了双向链表 Boxes in a Line UVA - 12657相关的知识,希望对你有一定的参考价值。

  首先记录一下对链表的理解,最初看链表是在教材上看的,上面是用结构体, 理解起来还不是很困难,我也以为自己懂了,然而看到紫书上链表用的是数组(UVA11988),真的是。。到最后把他的代码背下来了都还是有点晕(/(ㄒoㄒ)/~~),那个时候做题有点匆忙,也就没深究,不过后面那道(也就是这道)也就没再写了,差不多隔了一个月吧,有那么一点点感觉就是这次没看代码自己写过一遍后。

  单向每一个结构体有两个元素(或者更多),其中一个是下一个元素的地址,其他的是他本身有的东西,在这道题中,1 2 3 4 5, 2的next是3所在的地址,若操作要求把5放到3的左边,即1 2 5 3 4,这个时候2的next就是5所在的地址,双向其实就是加了个东西,就叫做before和after吧,在这个变化所要改的是2的after(3->5), 3的before(2->5), 4的after(5->NULL), 5的before(4->2)和after(NULL->3),看起来比数组要复杂一点,可是在100000这种范围里面,这样的一个指令如果用数组则要改变上万个数字的下标,而链表要改变的只是五六个数字而已。就大大减少了运行时间。这道题书上用的还是环形链表,只是加了个0,这样就不存在head和null,也不用考虑很多临界数据(我一开始用的是直链,以至于末尾数据的考虑占了绝大多数时间和代码量),挺棒的。 

 

  题意:对于一行按照顺序排列盒子,执行三种操作,command== 1, x 放到 y 的左边;==2, 右边; ==3 交换x, y;==4 全部顺序颠倒

  

  受到一个学长劝告,不要一昧的看别人的代码,如果思路实在想不到可以看看思路,但是编写的过程最好自己完成。

  对于这道题,由于有了一点对链表的理解,所以看到书上说这题需要用双向链表,认为自己可以独立写出来,就没看例题上的代码,用了七八小时,才使自己编写的程序对上了所有的数据(原题样例和ubudge里的样例),不过最后还是超时,没办法还是看了看书上的,发现原来是当command=4的时候我对所有盒子左右都颠倒了,这一步在n=100000的数据时非常的耗时,,,书上讲的inv的方法非常的棒,但是若移植到我的程序里面需要改动的地方实在太多,所以。。。我还是直接看书上的代码,看完后自己敲了一遍,由于自己已经花了这么多的时间去自己理解,所以这一步花的时间不算多。

  书上用的环形双向链表,用的不是结构体而是数组,想想由于同一种数据不是很多,用数组也确实更好,起码代码量特少,敲起来也简便

  最后通过了,不过不知道为什么时间是其他代码的三倍左右, 检查了一下思路确实一样,最后是把书上的代码抄了一遍,才发现原因竟然是。。。我用的是cin而不是scanf(O__O "…),第四章说cin慢我还不知道指什么,现在看来。。。好像是的( ~~~~(>_<)~~~~) 

  最后代码如下(其实没必要,与书上的差不多。。。)

#include <iostream>
#include <algorithm>
#include <cstdio>

using namespace std;
int lef[100005], rig[100005];
void link(int x, int y)
{
rig[x] = y; lef[y] = x;
}
int main()
{
int n, m, kase;
while(cin >> n >> m)
{
for(int i = 1; i <= n; i++)
{
lef[i] = i - 1;
rig[i] = (i + 1) % (n + 1);
}
rig[0] = 1; lef[0] = n;
int op, x, y, inv = 0;
while(m--)
{
scanf("%d", &op);
if(op == 4) inv = !inv;
else {
scanf("%d%d", &x, &y);
if(op == 3 && lef[x] == y) swap(x, y);
if(op != 3 && inv) op = 3 - op;
if(op == 1 && lef[y] == x) continue;
if(op == 2 && rig[y] == x) continue;
int xl = lef[x], xr = rig[x], yl = lef[y], yr = rig[y];
if(op == 1)
{
link(xl, xr); link(yl, x); link(x, y);
}
else if(op == 2)
{
link(xl, xr); link(y, x); link(x, yr);
}
else
{
if(rig[x] == y) {link(xl, y); link(y, x); link(x, yr); }
else {link(xl, y); link(y, xr); link(yl, x); link(x, yr); }
}
}

}
int b = 0;
long long ans = 0;
for(int i = 1; i <= n; i++)
{
b = rig[b];
if(i % 2) ans += b;
}
if(inv && n % 2 == 0) ans = (long long)n * (n + 1) / 2 - ans;
printf("Case %d: %lld\n", ++kase, ans);
}
return 0;
}

 

  做题反思:最大的收获就是觉得学长讲的挺有道理的,自己摸索的时间久是久了点,不过对于链表的理解却是深刻了许多,而且如果自己不写一遍,小错误不自己犯一遍,根本无法知道,比如这道题一开始写的时候,调试花很长时间的原因主要是对于一些特殊数据,临界数据的处理没有充分考虑,而且自己一开始用的是直链,少考虑的很多错误暴露了自己巨大的缺陷,也能督促自己以后要多留意这方面。还有一点,速度还是太慢了T_T.

以上是关于双向链表 Boxes in a Line UVA - 12657的主要内容,如果未能解决你的问题,请参考以下文章

Boxes in a Line UVA - 12657 (双向链表)

UVA 12657 Boxes in a Line(双向链表+小技巧)

UVa 12657 Boxes in a Line(数组模拟双链表)

Uva12657 (Boxes in a Line)移动盒子

UVA 12657 Boxes in a Line

Problem UVA12657-Boxes in a Line(数组模拟双链表)