1. 程式人生 > >Boxes in a Line UVA - 12657 (雙向鏈表)

Boxes in a Line UVA - 12657 (雙向鏈表)

.com 奇數 地方 namespace 找到 條件 amp print 思路

題目鏈接:https://vjudge.net/problem/UVA-12657

技術分享圖片

題目大意:輸入n,m 代表有n個盒子 每個盒子最開始按1~n排成一行 m個操作,

1 x y :把盒子x放到y的左邊

2 x y: 把盒子x放到y 的右邊

3 x y:調換x y盒子的位置

4 表示反轉整條鏈

思路:也是很明顯的暴力 模擬 。 但是值得提的是 雖然是暴力,但是卻是用的雙向鏈表來暴力。

有很多要註意的地方 :

當操作4的時候,我們可以把本次操作記錄一下,不必直接把全部的位置反轉 試想一下,如果每次出現一個4 每次都反轉 那多麻煩 (我們要反轉的話,首先得找到最後一個盒子,然後從最後一個盒子往前重新存儲一遍)

但是如果有記錄操作4註意再碰到其他操作 也要隨之改變 :

當有記錄4的時候 操作1就相當於操作2 操作2相當於操作1

還有註意的是 操作3 兩個盒子交換位置 : 兩個盒子相鄰和不相鄰是不一樣的 切記!!!

最後 要輸出結果的話 : 註意有沒有操作4 如果有操作4的話 如果是奇數 反轉一次對結果沒有影響 但是偶數 的話 反轉一次 我們現在求的剛好的偶數位的 總的減掉就是答案了

具體看代碼:

#include<iostream>
#include<string.h>
#include<vector>
#include
<stdio.h> using namespace std; const int maxn=1e5+5; int n; int Left[maxn]; int Right[maxn]; void link(int l,int r) //兩個節點相連 { Right[l]=r; Left[r]=l; } int main() { int m,ca=0; while(scanf("%d%d",&n,&m)!=EOF) { for(int i=1;i<=n;i++)//存好節點 { Left[i]
=i-1; Right[i]=(i+1)%(n+1);//這裏為何%(n+1) 試想一下 最後一個元素的右端是誰 顯然是第一個元素0 } Left[0]=n; Right[0]=1; int op,x,y,inv=0; while(m--) { scanf("%d",&op); if(op==4) inv=!inv;//相當於一種延遲標記 else { scanf("%d%d",&x,&y); if(op==3&&Right[y]==x) swap(x,y);// if(op!=3&&inv) op=3-op;//當調整一次順序的時候 操作1和2 剛好相反 可以自己舉例子 if(op==1&&x==Left[y]) continue;//已經滿足條件了 if(op==2&&x==Right[y]) continue; int lx=Left[x],rx=Right[x],ly=Left[y],ry=Right[y]; if(op==1) //調整位置 { link(lx,rx); link(ly,x); link(x,y); } else if(op==2) { link(lx,rx); link(x,ry); link(y,x); } else if(op==3)//註意兩者相連和不相連交換位置操作是不一樣的 !!! { if(Right[x]==y) // { link(lx,y); link(y,x); link(x,ry); } else { link(lx,y); link(y,rx); link(ly,x); link(x,ry); } } } } int b=0; long long ans=0; for(int i=1;i<=n;i++) { b=Right[b];//其實b就是i位置對應的值 可以仔細想一下 if(i%2==1) ans+=b; } if(inv&&n%2==0) ans=(long long)n*(n+1)/2-ans;//自己舉個例子就可以明白 n為奇數沒有影響 printf("Case %d: %lld\n",++ca,ans); } return 0; }

Boxes in a Line UVA - 12657 (雙向鏈表)