一行盒子 (湖南省第九届大学生程序设计大赛原题)

一行盒子

题意理解:

给一行数字(给出个数,从小到大从做到右排列),经过一些变化后,输出其顺序排在奇数位置上的数的和。

一个n,表示n个数顺序排列(1-n);

一个m,表示每次变化;

接着m次变化操作:

1 、u x y,把x移动到y的左边(u=1);

2 、u x y,把x移动到y的右边(u=2);

3 、u x y,把x和y的位置调换(u=3);

4 、u,把序列翻转过来,方向调转;


思路解析:


这个题目,在省赛回来后A出来,把代码贴上来,一直心痛,就没有再碰过。今天来写完它,真的是一道伤口,害怕揭开后的疼痛,是整个心都痉挛。


最开始的时候,对map和set不够熟悉,看到里面的insert(iterator,x),以为可以把键插到中间,直接就做了。这和比赛前一直用STL有关系,非常依赖STL。后面真的按照这个思想敲了,等我花了将近半小时敲完的时候才发现,即使是insert还是改变不了map里面的重头到尾的插入顺序,整个思想是对的,但是,map的插入方式却直接击溃了整个精神,当时离比赛结束只有20分钟,直接与AC无缘。这构成了我ACM人生的一大遗憾。最终,由于本题没能A出来,与奖杯距离六步之遥。。。再也不要“深藏功与名”!!


谨以此告诫所有主攻STL的同僚,要不就别学,要学就一定要搞清楚所以然,不要重蹈我的覆辙。


ACM毁大学,AC毁一生!


后来听说用双向链表可以过,自己写了个裸链表。。。答案是没问题,一提交就看到了TLE。郁闷了一整天后发现最耗时的是寻找节点的find()函数。果断改良,用map记录每个节点的地址(指针),在链表初始化的时候就初始化map的键。对于每个要移动的节点,先从链表中删除;然后再新建节点,插入到链表,同时更新map【见代码一】;对于方向,只要记录改变的次数,在操作处理时改变目标节点就可以了;最后计算的时候,直接按照方向从链表头和链表尾逐个编立计数,当计数变量为奇数的时候,累加节点的值,输出累加变量的值即可。


后面突发奇想,干脆不删除节点,直接将拿出来的要改变位置的节点插入到指定节点后面即可,不用更新map,也不必新建和删除节点,可以节约时间。于是就写了【代码二】,改进后的程序运行时间节约了72ms。时间不多,但是,思路更简洁了。改进了冗余部分。


个人感想:

省赛后,一直耿耿于怀,很久没有与AC约会,代码也打得少。快一个月了,回来机房打代码,打了没几行,有种热泪盈眶的感觉。当手指在键盘跳动,心里就是别有一番滋味。突然就想到前段时间去电子电工基地帮忙打文件,有人说“打代码的人就是不一样,敲键盘的节奏就不同”。当时小有感触,但也没放在心上。现在手指在键盘上游走,有种舍不得离开的感觉,就像就别重逢的恋人。说不出的。。。

本来就想着ACM,就这样算了,也奋斗这么久了,人也不小了,就这样吧。现在看来,好像还是放不下,还是不甘心,两年啊!都习以为常了,这种生活方式,这种带着耳机刷代码的感觉,忘不了,放不下。也许我只是累了,等我休息下,又回来了。

感觉的事情,谁说的定呢?

要命的熟悉的感觉,要命的苦涩与喜悦。

记得那些差一题的遗憾,那些独挡两题的兴奋,全然过去了。

还是没能在最后完成自己的愿望。

ACM毁大学,AC毁一生!

说起来都是泪(累)。

不知道能不能就这样算了。不知道能不能就这样放下!


【代码一】

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<map>
 
using namespace std;
 
int n,m;
long long ans;
 
struct node  //链表节点
{
    int x;
    struct node *first;  //前驱指针
    struct node *next;  //后继指针
}*head,*are,*p,*q;
 
map<int,node*> addre;
 
void initial()  //创建一个长度为n+2,赋值为1-n的带头结点和尾节点的双向链表
{
    head=(node *)malloc(sizeof(node));
    are=head;
    head->first=NULL;
    head->next=NULL;
    p=head;
    for(int i=1;i<=n;i++)
    {
        q=(node *)malloc(sizeof(node));
        p->next=q;
        q->first=p;
        q->next=NULL;
        q->x=i;
        addre[i]=q;
        p=q;
        are=q;
    }
    q=(node *)malloc(sizeof(node));
    p->next=q;
    q->first=p;
    q->next=NULL;
    are=q;
}
 
void gotozero()//  清空链表,释放所有节点,以免超内存
{
    p=are;
    while(p!=head)
    {
        q=p;
        p=p->first;
        free(q);
    }
    free(p);
    addre.clear();
}
 
node* find(int x)  //在链表中查找值为x的节点,返回该节点的指针
{
    p=head->next;
    while(p->x!=x)p=p->next;
    return p;
}
void delet(node* u)  //删除指针u指向的节点
{
    u->first->next=u->next;
    u->next->first=u->first;
    free(u);
}
 
void insert(node* u,int x)//在指针u指向的节点前面插入一个值为x的节点
{
    q=(node *)malloc(sizeof(node));
    q->x=x;
    addre[x]=q;
    q->first=u->first;
    q->next=u;
    u->first->next=q;
    u->first=q;
}
 
void cul1() //逆向处理
{
    int num=1;
    p=are->first;
    while(p!=head)
    {
        if(num%2==1)ans+=p->x;
        p=p->first;
        num++;
    }
}
 
void cul2()//正向处理
{
    int num=1;
    p=head->next;
    while(p!=are)
    {
        if(num%2==1)ans+=p->x;
        p=p->next;
        num++;
    }
}
 
void output()  //将链表按中节点的值按顺序输出
{
    p=head->next;
    while(p->next!=NULL)printf("%d ",p->x),p=p->next;
    printf("\n");
}
 
int main()
{
    int u,x,y;
    int i,j;int r=1;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        int flag=0;
        ans=0;
        initial();
 
        while(m--)
        {
            scanf("%d",&u);
            if(u==4)flag++;
 
            else
            {
                scanf("%d%d",&x,&y);
                if(u==1)
                {
                    delet(addre[x]);
                    if(flag%2==0)insert(addre[y],x);
                    else insert(addre[y]->next,x);
                }
 
                else if(u==2)
                {
                    delet(addre[x]);
                    if(flag%2==0)insert(addre[y]->next,x);
                    else insert(addre[y],x);
                }
 
                else
                {
                    q=addre[x];
                    p=addre[y];
                    q->x=y;
                    p->x=x;
                    addre[x]=p;
                    addre[y]=q;
                }
 
            }
            //output();
        }
 
        flag%2?cul1():cul2();
 
        printf("Case %d: %lld\n",r++,ans);
 
        gotozero();
 
    }
    return 0;
}
 
/**************************************************************
    Problem: 1329
    User: 20114045007
    Language: C++
    Result: Accepted
    Time:660 ms
    Memory:5652 kb
****************************************************************/


【代码二】

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<map>
 
using namespace std;
 
int n,m;
long long ans;
 
struct node  //链表节点
{
    int x;
    struct node *first;  //前驱指针
    struct node *next;  //后继指针
}*head,*are,*p,*q;
 
map<int,node*> addre;
 
void initial()  //创建一个长度为n+2,赋值为1-n的带头结点和尾节点的双向链表
{
    head=(node *)malloc(sizeof(node));
    are=head;
    head->first=NULL;
    head->next=NULL;
    p=head;
    for(int i=1;i<=n;i++)
    {
        q=(node *)malloc(sizeof(node));
        p->next=q;
        q->first=p;
        q->next=NULL;
        q->x=i;
        addre[i]=q;
        p=q;
        are=q;
    }
    q=(node *)malloc(sizeof(node));
    p->next=q;
    q->first=p;
    q->next=NULL;
    are=q;
}
 
void gotozero()//  清空链表,释放所有节点,以免超内存
{
    p=are;
    while(p!=head)
    {
        q=p;
        p=p->first;
        free(q);
    }
    free(p);
    addre.clear();
}
 
void delet()  //删除指针u指向的节点
{
    q->first->next=q->next;
    q->next->first=q->first;
}
 
void insert(node* u,int x)//在指针u指向的节点前面插入一个值为x的节点
{
    q->x=x;
    addre[x]=q;
    q->first=u->first;
    q->next=u;
    u->first->next=q;
    u->first=q;
}
 
void cul1() //逆向处理
{
    int num=1;
    p=are->first;
    while(p!=head)
    {
        if(num%2==1)ans+=p->x;
        p=p->first;
        num++;
    }
}
 
void cul2()//正向处理
{
    int num=1;
    p=head->next;
    while(p!=are)
    {
        if(num%2==1)ans+=p->x;
        p=p->next;
        num++;
    }
}
 
int main()
{
    int u,x,y;
    int i,j;int r=1;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        int flag=0;
        ans=0;
 
        if(r!=1)gotozero();
 
        initial();
 
        while(m--)
        {
            scanf("%d",&u);
            if(u==4)flag++;
 
            else
            {
                scanf("%d%d",&x,&y);
                if(u==1)
                {
                    q=addre[x];
                    delet();
                    if(flag%2==0)insert(addre[y],x);
                    else insert(addre[y]->next,x);
                }
 
                else if(u==2)
                {
                    q=addre[x];
                    delet();
                    if(flag%2==0)insert(addre[y]->next,x);
                    else insert(addre[y],x);
                }
 
                else
                {
                    q=addre[x];
                    p=addre[y];
                    q->x=y;
                    p->x=x;
                    addre[x]=p;
                    addre[y]=q;
                }
 
            }
        }
 
        flag%2?cul1():cul2();
 
        printf("Case %d: %lld\n",r++,ans);
 
    }
    return 0;
}
/**************************************************************
    Problem: 1329
    User: 20114045007
    Language: C++
    Result: Accepted
    Time:588 ms
    Memory:5652 kb
****************************************************************/


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值