Vijos P1008 篝火晚會

Vijos P1008 篝火晚會


描述

佳佳剛進高中,在軍訓的時候,由於佳佳吃苦耐勞,很快得到了教官的賞識,成爲了“小教官”。在軍訓結束的那天晚上,佳佳被命令組織同學們進行篝火晚會。一共有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。
樣例1

樣例輸入1

4
3 4
4 3
1 2
1 2

樣例輸出1

2

限制

1s


題解

考慮到如果該數據有解,那麼一定會以節點1 先向左/右走一步,那麼這整個環就確定下來了,但是它會有兩個(鏡像環)

然後就是用一個貪心的方法,從環上任意一個節點開始走,求出走到該點所要的時間,以及改點的id 他們的差值,記錄這個差值

顯然,某個差值出現次數越多,說明以這些差值出現的節點所構成的環所需要調整的人數越少,答案就是 n -出現次數的最大值

然後,就是判斷是否存在解

首先,對於一個節點,它被需要的次數超過2 次 ,那麼一定不存在解,因爲是一個環,一個人的臨近位置只有兩個

其次,對於一個環,如果他不能包括所有的點,那麼它也一定不存在解(數據的第二個點,我開始只A 了第二個點,所以知道)

最後,對於一個點,如果它上一個點的下一個點不是它自己,那麼它也沒有解(好像這個只適用於起點,反正我也寫上去了)


代碼

#include<cstdio>
#include<cstring>
#define maxn 50005
using namespace std;

int n,tot,ans,last;
int p[maxn],cnt[maxn],l[maxn],r[maxn],hash[maxn];
bool vis[maxn];

int readln()
{
    int x=0;
    char ch=getchar();
    while (ch<'0'||ch>'9') ch=getchar();
    while ('0'<=ch&&ch<='9') x=x*10+ch-48,ch=getchar();
    return x;
}

int max(int x,int y){return x>y?x:y;}

int main()
{
    n=readln();
    for (int i=1;i<=n;i++)
    {
        l[i]=readln();r[i]=readln();
        cnt[l[i]]++;cnt[r[i]]++;
        if (cnt[l[i]]>2||cnt[r[i]]>2) {printf("-1");return 0;}
    }
    last=l[1];
    for (int i=1;!vis[i];i=(vis[r[i]]?l[i]:r[i]))
    {
        vis[i]=true;
        if (l[last]!=i&&r[last]!=i) {printf("-1");return 0;}
        p[++tot]=i;hash[(i-tot+n)%n]++;last=i;
    }
    if (tot<n) {printf("-1");return 0;}
    for (int i=0;i<n;i++) ans=max(ans,hash[i]);
    memset(vis,false,sizeof(vis));
    memset(hash,0,sizeof(hash));
    tot=0;
    for (int i=1;!vis[i];i=(vis[l[i]]?r[i]:l[i]))
    {
        vis[i]=true;
        p[++tot]=i;hash[(i-tot+n)%n]++;
    }
    for (int i=0;i<n;i++) ans=max(ans,hash[i]);
    printf("%d",n-ans);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章