一行盒子 (湖南省第九屆大學生程序設計大賽原題)

一行盒子

題意理解:

給一行數字(給出個數,從小到大從做到右排列),經過一些變化後,輸出其順序排在奇數位置上的數的和。

一個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 ****************************************************************/


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章