题目:
一个整数组里包含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.