1. 程式人生 > >Boxes in a Line UVA

Boxes in a Line UVA

題目:

對一行陣列有四種操作:

1.把數字x放到數字y的左邊

2.把數子X放到數字Y的右邊

3.交換X和Y的位置

4.把所有數字翻轉順序

思路:

如果用陣列的話,明顯第四個操作就會明顯超時。所以採用連結串列。用連結串列模擬一下就行。此處採用陣列模擬連結串列實現

對於第四種操作,可以用一個變數去判斷是否翻轉,如果翻轉的話,只需要把原來的左右指標交換即可。

注意交換的時候,兩個數字相鄰和兩個數字不相鄰是兩種不同的方式。

程式碼:

/*by kzl*/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>

using namespace std;
const int maxx = 1e5+500;
const int INF = 0x3f3f3f3f;
typedef long long LL;

int n,m,a,x,y;
int lnext[maxx],rnext[maxx];
long long sum = 0;
void init()
{
    for(int i=1; i<=n; i++)rnext[i] = i+1,lnext[i] = i-1;
    rnext[0] = 1;lnext[0] = n;rnext[n] = 0;
    sum = 0;
}

void one(int l[],int r[],int x,int y){
    if(l[y]==x)return;
    l[r[x]] = l[x]; //把X從列表中刪除
    r[l[x]] = r[x];

    r[l[y]] = x;//將x插入到y左側
    l[x] = l[y];
    r[x] = y;
    l[y] = x;
}

void two(int l[],int r[],int x,int y){
    if(r[y]==x)return;
    l[r[x]] = l[x]; //把X從列表中刪除
    r[l[x]] = r[x];
    //將x插入到y右側
    l[r[y]] = x;
    r[x] = r[y];
    r[y] = x;
    l[x] = y;
}

void three(int l[],int r[],int x,int y){
    if(r[y]==x)swap(x,y);
    if(r[x]==y){
        r[x] = r[y];
        l[r[y]] = x;
        l[y] = l[x];
        r[l[x]] = y;
        r[y] = x;
        l[x] = y;
        return ;
    }
    int cc = r[x],dd = l[x];
    l[r[y]] = x;r[l[y]] = x;
    r[x] = r[y];l[x] = l[y];
    l[cc] = y;r[dd] = y;
    r[y] = cc;l[y] = dd;
}

void getsum(int ne[]){
    for(int i = ne[0],j=1;i!=0;i = ne[i],j++){
        if(j&1&&i<=n)sum+=i;
    }
}

int main()
{
    int num = 1;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        int flag = 0;
        for(int i=0; i<m; i++)
        {
            scanf("%d",&a);
            if(a==1) //move box X to the left to Y
            {
                scanf("%d%d",&x,&y);
                if(flag==0)
                {
                    one(lnext,rnext,x,y);
                }
                else one(rnext,lnext,x,y);
            }
            else if(a==2)
            {
                scanf("%d%d",&x,&y);
                if(flag==0)
                {
                    two(lnext,rnext,x,y);
                }
                else two(rnext,lnext,x,y);
            }
            else if(a==3)
            {
                scanf("%d%d",&x,&y);
                if(flag==0)
                {
                    three(lnext,rnext,x,y);
                }
                else three(rnext,lnext,x,y);
            }
            else if(a==4)
            {
                flag = flag^1;
            }
        }
        if(flag==0)getsum(rnext);
        else getsum(lnext);
        printf("Case %d: %lld\n",num++,sum);
    }
    return 0;
}

可優化:

以上程式碼可以有以下優化:

1.連線兩個節點的操作可以寫成一個函式,節省程式碼。

2.對於4操作,因為因為他隻影響了1,2的順序,而且1,2操作相對來說正好關於4操作對稱,所以翻轉之後的1操作實際就是之前的2操作。而不必要翻轉指標。