题目:
一个整数组里包含0-(n-1)的排列 (0到(n-1)恰好只出现一次),如果每次只允许把任意数和0交换,求排好顺序至少交换多少次。
思路:
这是组合数学中的圈问题,可以把数组中的位置关系看成图的拓扑关系。
例如A[3]={2,0,1},2在0的位置,0在1的位置,1在2的位置,那么把它们画成图的拓扑结构的话,就是一个环(圈),即2->0->1->2。
这样的条件(排列成环(圈))用文字描述为:1、位置和位置上的数字或字符存在一一对应关系;2、每个数字或字符都不在自己应有的位置上;
上例我们通过交换1和0,再交换2和0,即可正确排序,次数为2.
一个排序总可以划分为不同的环(圈),独立成圈的不需要交换;
总结满足上述条件的规律:
- 一个长度为m的圈,如果包含0,则交换(m -1)次可以恢复所有的数到原位
- 一个长度为m的圈,如果不包含0,则交换(m+ 1) 次可以恢复所有的数到原位
代码:
#include <iostream>
using namespace std;
int circle(int A[],bool isvisited[],int x){
int count=0;
while(!isvisited[x]){
count++;
isvisited[x]=true;
x=A[x];
}
if(count==0)
return 0;
else
return count-1;
}
int main()
{
int A[]={1,3,2,4,6,5,0};
int n=sizeof(A)/sizeof(A[0]);
bool isvisited[n];
for(int i=0;i<n;i++)
isvisited[i]=false;
int count=0;
for(int i=0;i<n;i++){
count+=circle(A,isvisited,A[i]);
}
cout << count << endl;
return 0;
}
运行结果:
4
该数组划分为3个圈,其中2和5独立成圈,无需交换,而其他五个数成圈,1->3->4->6->0->1,交换次数为5-1=4.