算法竞赛入门经典 第二版 例题6-5 移动盒子 Boxes in a Line uva12657

题目:https://vjudge.net/problem/UVA-12657


思路:题目很短也很好理解,但题目时限要求较高,uva上的题目时限大多是3s,这题1s,起初我用STL的list容器做果不其然超时了,刘汝佳给出的双向链表的数组实现又实在是晦涩难懂,即便看懂了我也没能力独立写出来。STL list超时的主要原因是查询元素的时间代价太大,停滞了两天后我突然想到可以用一个指针数组下标存值来辅助建立传统双向链表,这样就通过下标可以直接访问指向链表节点的元素,完全省略了查找过程。话是这么说,但双向链表的操作异常繁琐,需要处处小心。

还有一些技巧,书中已经提到了,比如利用标记记录链表是否逆序,而并不反转指针方向,借以提高运行效率。


代码:C++


#include <iostream>
#include <cstdio>
#include <list>
#include <algorithm>
using namespace std;

const int maxn = 100000+10;

struct List
{
    int value;
    List *next;
    List *prevous;
    List(int i):value(i){}
};

List *data[maxn] = {NULL};
List *first;
List *last;
bool isreversed;

void creatList(int n)
{
    data[0] = NULL;
    for(int i = 1; i<=n; i++)
    {
        data[i] = new List(i);
        data[i]->prevous = data[i-1];
    }
    for(int i = 1; i<=n-1; i++)
    {
        data[i]->next = data[i+1];
    }
    data[n]->next = NULL;
    first = data[1];
    last = data[n];
}

void clearList(int n)
{
    first = NULL;
    last = NULL;
    for(int i = 1; i<=n; i++)
    {
        delete data[i];
        data[i] = NULL;
    }
}

void removelink(int x)
{
    if(last==data[x])
    {
        data[x]->prevous->next = NULL;
        last = data[x]->prevous;
    }
    else if(first==data[x])
    {
        first = data[x]->next;
        data[x]->next->prevous = NULL;
    }
    else
    {
        data[x]->prevous->next = data[x]->next;
        data[x]->next->prevous = data[x]->prevous;
    }
}

void moveleft(int x, int y)
{
    if(data[y]->prevous==data[x])
    {
        return;
    }
    removelink(x);
    if(first==data[y])
    {
        first = data[x];
        data[x]->prevous = NULL;
        data[x]->next = data[y];
        data[y]->prevous = data[x];
    }
    else
    {
        data[y]->prevous->next = data[x];
        data[x]->next = data[y];
        data[x]->prevous = data[y]->prevous;
        data[y]->prevous = data[x];
    }
}

void moveright(int x, int y)
{
    if(data[y]->next==data[x])
    {
        return;
    }
    removelink(x);
    if(last==data[y])
    {
        data[y]->next = data[x];
        data[x]->prevous = data[y];
        last = data[x];
        data[x]->next = NULL;
    }
    else
    {
        data[y]->next->prevous = data[x];
        data[x]->next = data[y]->next;
        data[y]->next = data[x];
        data[x]->prevous = data[y];
    }
}

void swapbox(int x, int y)
{
    if(first==data[x])
    {
        int rightx = data[x]->next->value;
        moveright(x, y);
        if(y!=rightx)
            moveleft(y, rightx);
    }
    else
    {
        int leftx = data[x]->prevous->value;
        moveleft(x, y);
        if(y!=leftx)
            moveright(y, leftx);
    }
}

void solve(int order, int x, int y)
{
    if(!isreversed)
    {
        switch(order)
        {
            case 1: moveleft(x, y); break;
            case 2: moveright(x, y); break;
            case 3: swapbox(x, y); break;
            case 4: isreversed = !isreversed; break;
        }
    }
    else
    {
        switch(order)
        {
            case 1: moveright(x, y); break;
            case 2: moveleft(x, y); break;
            case 3: swapbox(x, y); break;
            case 4: isreversed = !isreversed; break;
        }
    }
}

long long getoddsum()
{
    long long sum = 0;
    if(!isreversed)
    {
        List *p;
        int i = 1;
        for(p = first; p!=NULL; p = p->next, i++)
        {
            if(i%2==1)
            {
                sum += p->value;
            }
        }
    }
    else
    {
        List *p;
        int i = 1;
        for(p = last; p!=NULL; p = p->prevous, i++)
        {
            if(i%2==1)
            {
                sum += p->value;
            }
        }
    }
    return sum;
}

int main()
{
    int n, m, serial = 1;
    int order, x, y;
    while(scanf("%d%d", &n, &m)!=EOF)
    {
        creatList(n);
        isreversed = false;
        while(m--)
        {
            scanf("%d", &order);
            if(order!=4)
                scanf("%d%d", &x, &y);
            solve(order, x, y);
        }
        printf("Case %d: %lld\n", serial++, getoddsum());
        clearList(n);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值