您的位置:首页 > 其它

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

2013-10-16 21:41 465 查看

一行盒子

题意理解:

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

一个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
****************************************************************/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  STL 链表 malloc 指针 map