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

一行盒子

題意理解:

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

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


發佈了150 篇原創文章 · 獲贊 35 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章