UVa 12657 Boxes in a Line解析代码

本文详细解析了一种基于数组实现的双向链表操作方法,并通过一个具体的编程实例展示了如何进行节点插入、删除等操作。文章重点介绍了链接函数的实现原理及其在实际应用中的技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

紫书上的链表部分是基于数组的,不同于数据结构书上使用基于指针的链表。这样一来代码读起来就会有点晦涩难懂。这题也不例外,这里主要是练习使用 双向链表

先看看这两个数组:

const int maxn = 100000 + 5;
int n, left[maxn], right[maxn];

left数组中保存着每个盒子的左边的盒子的编号,right也就是保存着每个盒子右边的盒子编号。

然后看看这个link()函数吧:

inline void link(int L, int R) {
  right[L] = R; left[R] = L;
}

这个函数的主要作用要明确,就是接收两个盒子的编号(L,R),并将其连接起来。怎么连接呢?函数中写的十分清楚。将L的右边设置为R,将R的左边设置为L。即 … – L – R – … 。这样一来不就连起来了吗。

再来看看main()函数:

int main() {
  int m, kase = 0;
  while(scanf("%d%d", &n, &m) == 2) {
    for(int i = 1; i <= n; i++) {
      left[i] = i-1;
      right[i] = (i+1) % (n+1);   //这里主要是为了将right[n] = 0;
    }
    right[0] = 1; left[0] = n;
    int op, X, Y, inv = 0;

    while(m--) {
      scanf("%d", &op);
      if(op == 4) inv = !inv;  //这里是本题的一个技巧。inv为1表示反链表,为0表示原链表
      else {
        scanf("%d%d", &X, &Y);
        if(op == 3 && right[Y] == X) swap(X, Y);  //这也是一个技巧,这里在下面会体现出
        if(op != 3 && inv) op = 3 - op;  //如果是反链表,就将操作1和操作2交换。
        if(op == 1 && X == left[Y]) continue;
        if(op == 2 && X == right[Y]) continue;

        int LX = left[X], RX = right[X], LY = left[Y], RY = right[Y];
        if(op == 1) {
          link(LX, RX); link(LY, X); link(X, Y);
        }
        else if(op == 2) {
          link(LX, RX); link(Y, X); link(X, RY);
        }
        else if(op == 3) {
          //这里就体现swap(X, Y)的作用了,当编号为X和Y的两个箱子相邻时我们需要特殊处理。
          if(right[X] == Y) { link(LX, Y); link(Y, X); link(X, RY); }
          else { link(LX, Y); link(Y, RX); link(LY, X); link(X, RY); }
        }
      }
    }

    int b = 0;
    long long ans = 0;
    for(int i = 1; i <= n; i++) {
      b = right[b];   //这里就把其当作一个单向链表来处理即可
      if(i % 2 == 1) ans += b;
    }
    if(inv && n % 2 == 0) ans = (long long)n*(n+1)/2 - ans;
    printf("Case %d: %lld\n", ++kase, ans);
  }
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值