原题链接:
一看这道题就想到了离散上学的置换群,按置换群做了做,果然AC了!
先讲一下思考过程:
index: 1 2 3 4 5 6 7 8 9
原数据: 2 2 1 3 3 3 2 3 1
排序后: 1 1 2 2 2 3 3 3 3
分组后 index: 1 3 2 9 5 4 7 6 8
2 1 2 1 3 3 2 3 3
1 2 1 3 2 2 3 3 3
从上面的分组可看出第一组和第三组交换一次,第二组和第五组交换一次,第五组再和第九组交换一次,第四组和第七组交换一次,这样一共交换了4次,
就是答案了!
关键是如何进行分组呢?这就用到了离散上的知识,将群转换为轮换和对换之积的形式,然后分别计算出对换或轮换中数的个数再减一就是交换的次数,把
所有次数累加就是总的交换次数了。但是要注意一种情况如果找的轮换是如下形式,则要进行处理在计算次数:
2 1 3 1 3 ----------> 2 1 3 3 1
1 3 1 3 2 1 3 2 1 3
这组数据有个特点就是轮换之中包含着对换,直接计算交换次数是4次,但是我们可以把它拆成右边的两组,交换次数变为2+1=3次。显然右边的交换次数少,
是我们需要的。当遇到这种数据时,方法是找出轮换中对换的个数,然后总的次数减去对换的个数。在此例中有一个对换,就是4-1=3了。
源代码:
/*
ID: supersnow0622
PROG: sort3
LANG: C++
*/
#include <iostream>
#include <fstream>
#include <string>
#include<algorithm>
#include<memory.h>
using namespace std;
int arr[1001],byOrder[1001],used[1001],judge[4];
int main() {
ofstream fout ("sort3.out");
ifstream fin ("sort3.in");
int N,start,count;
cin>>N;
for(int i=0;i<N;i++)
{
cin>>arr[i];
byOrder[i]=arr[i];
}
sort(byOrder,byOrder+N);
int index,temp,sum=0;
for(int i=0;i<N;i++)
if(arr[i]==byOrder[i])
used[i]=1;
for(int i=0;i<N;i++)
{
memset(judge,0,sizeof(judge));
if(!used[i]){
start=arr[i];
count=0;
judge[start]=1;
used[i]=1;
index=i;
while(byOrder[index]!=start)
{
sum++;
temp=byOrder[index];
int j;
for(j=0;j<N;j++)
{
if(arr[j]==temp&&!used[j])
{
judge[temp]=1;
used[j]=1;
break;
}
}
index=j;
if(judge[byOrder[index]]==1)
{
memset(judge,0,sizeof(judge));
judge[start]=1;
count++;
}
}
if(count!=1)
sum=sum-count+1;
}
}
cout<<sum;
return 0;
}