Problem Description
HDU ACM集訓隊的隊員在暑假集訓時經常要討論自己在做題中遇到的問題.每當面臨自己解決不了的問題時,他們就會圍坐在一張圓形的桌子旁進行交流,經過大家的討論後一般沒有解決不了的問題,這也只有HDU ACM集訓隊特有的圓桌會議,有一天你也可以進來體會一下哦:),在一天在討論的時候,Eddy想出了一個極爲古怪的想法,如果他們在每一分鐘內,一對相鄰的兩個ACM隊員交換一下位子,那麼要多少時間才能得到與原始狀態相反的座位順序呢?(即對於每個隊員,原先在他左面的隊員後來在他右面,原先在他右面的隊員在他左面),這當然難不倒其他的聰明的其他隊友們,馬上就把這個古怪的問題給解決了,你知道是怎麼解決的嗎?
Input
對於給定數目N(1<=N<=32767),表示有N個人,求要多少時間才能得到與原始狀態相反的座位順序(reverse)即對於每個人,原先在他左面的人後來在他右面,原先在他右面的人在他左面。
Output
對每個數據輸出一行,表示需要的時間(以分鐘爲單位)
Sample Input
4 5 6
Sample Output
2 4 6
解題思路:
如果是所有人排列成一條直線,那麼移動的思想與冒泡排序一樣,總共需要n*(n-1)/2種方法,
求環形的逆序變換最小時間,因爲環形是相互連接的,那麼只要將n劃分爲最接近的兩個直線,
當這兩個劃分的直線逆序了。那麼整條環形便也逆序了。
圓桌移動要分成兩段,證明:
這題就是在求一串數在每次只能對調相鄰兩位時,要得到其逆序最少要移動多少次。在直線上移動很簡單,類似於冒泡排序的方法,一個數不斷向上冒,直到最終位置。不難得到其需要移動的次數公式爲n*(n-1)/2。其中n爲總點數。那麼在圓環上移動又會如何呢?應該會不一樣這是我們直觀的感受。事實也是如此,移動的過程是將圓環分爲兩段,分別移動。那麼又在何處分段呢?
答案是儘量使兩段長度相等。爲啥?
證明如下:
設n爲總長度,分爲兩段,長度分別爲a、b。總次數=a*(a-1)/2+b*(b-1)/2=a*(a-1)/2+(n-a)*(n-a-1)/2=(2*a^2-2*n*a+n^2)/2。其中n爲常量,a爲變量。二次曲線開口向上,最小值對應的a=-(-2*n)/(2*2)=n/2。顯然a要求整數。我們需要將這個圈換成兩條線的辦法,舉個簡單的例子來說,我們爲了換一條直線的1234爲4321,需要將4先換到最前面,然後3,後2,後1,然後我們就可以求出了爲n*(n-1)/2,然後我們在做一個圈時,如果是123456,我們可以把12逆序,再逆序3456,可以逆序123,然後逆序456,所以我們的問題在於怎麼才能找到一個點讓其最小,一般如果是蒙的話是蒙一半,但實際也是這麼回事,s=a*(a-1)/2+(n-a)*(n-a-1)/2,這樣在去求其最小值,用x=-b/2*a,可得x=n/2最小了,所以就這麼做出來了!!!!!!!!!!
上面的題解是百度的別人的博客,實話實說,看完之後我是一臉懵逼,後來請教了一下大神才終於明白這題解題思路到底什麼意思。。。。。。
假如說有8個人,a b c ,圍成一個環,將環切成兩段:a,b,c,d e,f,g,h ;現在以a爲起點,開始寫出交換後兩邊的人,交換後的結果,a h g ,將環切成兩段:h,g,f,e d,c,b,a; 你
h d b f
g f e c d e
會發現這兩段正好和交換前的相反;那就簡單了,將環儘量平均的分成m,n-m兩段(至於爲什麼平均上面解釋的有);然後最後的次數就爲m*(m-1)/2+(n-m)*(n-m-1)/2;
//AC
#include<stdio.h>
int main()
{
int n;
while (scanf("%d",&n)!=EOF)
{
int a;
a=n/2;
int num=0;
num=a*(a-1)/2+(n-a)*(n-a-1)/2;
printf("%d\n",num);
}
return 0;
}