描述
佳佳剛進高中,在軍訓的時候,由於佳佳喫苦耐勞,很快得到了教官的賞識,成爲了“小教官”。在軍訓結束的那天晚上,佳佳被命令組織同學們進行篝火晚會。一共有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;
}
據說冒泡也可以做?
表示不理解 順帶求講解