圓桌會議

圓桌會議
Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)


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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章