VIJOS 1008 篝火晚會

描述

佳佳剛進高中,在軍訓的時候,由於佳佳喫苦耐勞,很快得到了教官的賞識,成爲了“小教官”。在軍訓結束的那天晚上,佳佳被命令組織同學們進行篝火晚會。一共有n個同學,編號從1到n。一開始,同學們按照1,2,……,n的順序坐成一圈,而實際上每個人都有兩個最希望相鄰的同學。如何下命令調整同學的次序,形成新的一個圈,使之符合同學們的意願,成爲擺在佳佳面前的一大難題。

佳佳可向同學們下達命令,每一個命令的形式如下:

(b1, b2,... bm -1, bm)

這裏m的值是由佳佳決定的,每次命令m的值都可以不同。這個命令的作用是移動編號是b1,b2,…… bm –1,bm的這m個同學的位置。要求b1換到b2的位置上,b2換到b3的位置上,……,要求bm換到b1的位置上。

執行每個命令都需要一些代價。我們假定如果一個命令要移動m個人的位置,那麼這個命令的代價就是m。我們需要佳佳用最少的總代價實現同學們的意願,你能幫助佳佳嗎?

對於30%的數據,n <= 1000;

對於全部的數據,n <= 50000。

格式

輸入格式

輸入的第一行是一個整數n(3 <= n <= 50000),表示一共有n個同學。其後n行每行包括兩個不同的正整數,以一個空格隔開,分別表示編號是1的同學最希望相鄰的兩個同學的編號,編號是2的同學最希望相鄰的兩個同學的編號,……,編號是n的同學最希望相鄰的兩個同學的編號。

輸出格式

輸出包括一行,這一行只包含一個整數,爲最小的總代價。如果無論怎麼調整都不能符合每個同學的願望,則輸出-1。

樣例

樣例輸入

4
3 4
4 3
1 2
1 2

樣例輸出

2

限制

1s

來源

NOIp2005 第三題




一開始真不會 感覺 這tm怎麼做啊。。。

後來自己讀題

原來b1,b2......bm與1,2,3......m沒有任何關係

b1可以是1 可以是2 也可以是3...

那麼這樣的話 所有位置不匹配的 一次就可以換對位置!

我們就要去找位置不匹配的最小人數

(據說這是置換羣,蒟蒻表示真心不知道。。。)


首先判斷-1 假如a想和b在一起 b不想和a在一起 那麼肯定不能實現願望  就輸出-1


一開始給的序列是1...n

即f[i]=i

目標序列其實有2個

1想要和l[1],r[1]在一起 可以1,l[1],......,r[1]

也可以1,r[1],.......,l[1]

可以用BFS生成這兩個序列g(DFS會爆棧。。。)

然後與一開始的序列比較


因爲序列是一個環

1 2 3 4 5

2 3 4 5 1

4 5 1 2 3

是等價的


所以g[i]與i是相對的

如果所有g[i]-i都大於1 那麼旋轉一下 所有g[i]=i

所以我們不應只認爲g[i]=i是符合的

事實上 max{T[k]},(k=g[i]-i , 1<=i<=n)是符合最多的人數

只要都和下標i差同一個數 旋轉這個數後 就都和下標相同了


因爲c++沒有負下標

所以可以 (g[i]-i+n)%n

g[i]-i+n處理負下標

%n防止出現g[i]>i時   g[i]-i+n>0的情況  因爲n個人 第1個和數一圈後的第n+1個人其實是一個人


代碼如下  生成p序列一開始寫的dfs 7個點RE

後怕啊 多虧不是考試。。。

然後寫了個比較難看的bfs生成序列


#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int g[50055][2];
int a,b,c;
int m,z=999999999;
int num[250055],hash=100001;
int xulie[50055];
bool use[50055][2];

int i;
void bfs()
{
    int i=2,ret=0,k;
    xulie[1]=1;
    xulie[2]=g[1][0];
    use[1][0]=1;
    if(g[g[1][0]][0]==1)use[g[1][0]][0]=1;else use[g[1][0]][1]=1;
    while(i<=m)
    {
        int now=xulie[i];
        for(int k=0;k<=1;k++)
        if(!use[now][k])
        {
            use[now][k]=1;
            if(g[g[now][k]][0]==now)use[g[now][k]][0]=1;
            else use[g[now][k]][1]=1;
            i++;
            xulie[i]=g[now][k];
        }
        
    }
    memset(num,0,sizeof(num));
    for(int a=1;a<=m;a++)
    {
        k=(xulie[a]-a+m)%m;
        num[k]++;
        ret=max(ret,num[k]);
    }
    z=min(z,(m-ret));
    
    i=2;
    memset(xulie,0,sizeof(xulie));memset(use,0,sizeof(use));
    xulie[1]=1;
    xulie[2]=g[1][1];
    use[1][1]=1;
    if(g[g[1][1]][0]==1)use[g[1][1]][0]=1;else use[g[1][1]][1]=1;
    while(i<=m)
    {
        int now=xulie[i];
        for(int k=0;k<=1;k++)
        if(!use[now][k])
        {
            use[now][k]=1;
            if(g[g[now][k]][0]==now)use[g[now][k]][0]=1;
            else use[g[now][k]][1]=1;
            i++;
            xulie[i]=g[now][k];
        }
        
    }
    
    ret=0;
    memset(num,0,sizeof(num));
    for(int a=1;a<i;a++)
    {
        k=(xulie[a]-a+m)%m;
        num[k]++;
        ret=max(ret,num[k]);
    }
    z=min(z,(m-ret));
}

int main()
{
    scanf("%d",&m);
    for(a=1;a<=m;a++)scanf("%d%d",&g[a][0],&g[a][1]);
    
    for(a=1;a<=m;a++)
    {
        if(g[g[a][0]][0]!=a&&g[g[a][0]][1]!=a){cout<<"-1"<<'\n';return 0;}
        if(g[g[a][1]][0]!=a&&g[g[a][1]][1]!=a){cout<<"-1"<<'\n';return 0;}
    }
    bfs();
    cout<<z<<endl;
    return 0;
}


據說冒泡也可以做?

表示不理解 順帶求講解

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章