【POJ 2370】Cow Sorting(置换群)
Cow Sorting
Description Farmer John's N (1 ≤ N ≤ 10,000) cows are lined up to be milked in the evening. Each cow has a unique "grumpiness" level in the range 1...100,000. Since grumpy cows are more likely to damage FJ's milking equipment, FJ would like to reorder the cows in line so they are lined up in increasing order of grumpiness. During this process, the places of any two cows (not necessarily adjacent) can be interchanged. Since grumpy cows are harder to move, it takes FJ a total of X+Y units of time to exchange two cows whose grumpiness levels are X and Y. Please help FJ calculate the minimal time required to reorder the cows. Input
Line 1: A single integer: N.
Lines 2..N+1: Each line contains a single integer: line i+1 describes the grumpiness of cow i. Output
Line 1: A single line with the minimal time required to reorder the cows in increasing order of grumpiness.
Sample Input 3 2 3 1 Sample Output 7 Hint
2 3 1 : Initial order.
2 1 3 : After interchanging cows with grumpiness 3 and 1 (time=1+3=4). 1 2 3 : After interchanging cows with grumpiness 1 and 2 (time=2+1=3). Source |
[Submit] [Go Back] [Status] [Discuss]
[题意][将给定的序列转换成按升序排列所需的最小步数]
【题解】【置换群模板题】
任一集合A到自身的映射都叫做A的一个变换,如果A是有限集且变换 是一一变换(双射),那么这个变换为A的一个置换。
有限集合A的若干个置换若作成群,就叫做置换群。含有n个元素的有 限群A的全体置换作成的群,叫做n次对称群。通常记为sn.
例如给出一排数8 4 5 3 2 7,那么我们最终的状态为2 3 4 5 7 8,这里的轮换(也可以说是一个循环节)有(8 2 7)(4 5 3),即对于(8 2 7)这个轮换,我们需要把2换到8的位置,7换到2的位置,8换到7的位置,我们称这是一个轮换。那么对于每个轮换的内部操作我们考虑如何最优呢?因为要使代价最小,那么我们就尽量不移动大的数,移动小的数,每次把轮换中最小的数与轮换中的其他数交换K-1次,就可以得到我们想要的轮换后的序列(其中K为轮换中数的个数),此时的代价为sum-min+(k-1)*min(其中sum为轮换组中的总和,min为轮换中的最小值)
那是否还有更优的操作呢?我们可以找出序列中最小的数,然后与轮换中的最小的数交换,用这个序列中最小的数与轮换中的数进行交换(即代替原来的最小的数进行上述的操作),操作完成后,在将序列中最小的数与轮换中原本最小的数交换回去,即可,这时的代价为sum+min+(k+1)*minnum。
我们只需要每次寻找出轮换,然后从两种方式中选择代价小的进行操作即可。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,a[100010],num[100010],maxn,minn=0x7fffffff,ans;
bool p[100010];
int main()
{
int i,j;
scanf("%d",&n);
for(i=1;i<=n;++i)
{
scanf("%d",&a[i]);
num[a[i]]++;
maxn=max(maxn,a[i]); minn=min(minn,a[i]);
}
for(i=1;i<=maxn;++i) num[i]+=num[i-1];
for(i=1;i<=n;++i)
if(!p[i])
{
int t=0,mm=0x7fffffff,sum=0; j=i;
while(!p[j])
{
t++; sum+=a[j];
mm=min(mm,a[j]);
p[j]=1; j=num[a[j]];
}
if(t>1) ans+=sum;
if(t>=2)
{
int s1=-mm+(t-1)*mm; int s2=mm+(t+1)*minn;
ans+=min(s1,s2);
}
}
printf("%d",ans);
return 0;
}