给出一个长度不超过500的环状排列,每次操作可以交换任意两个数,求把这个排列变成有序的环状排列所需的最小操作次数。
首先把环状排列的起点固定使其成为链状排列a,枚举排好序时的状态b(一种有2n种可能),则b可以看成是原状态a的一个置换,把a变为b所需的最小交换次数即为a的长度n减去置换循环节的数量。
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 typedef long long ll; 5 const int N=500+10; 6 const int inf=0x3f3f3f3f; 7 int n,a[N],b[N],c[N],vis[N],ans; 8 9 int cir(int* a,int* b,int n) { 10 int ret=0; 11 memset(vis,0,sizeof vis); 12 for(int i=1; i<=n; ++i)c[a[i]]=b[i]; 13 for(int i=1; i<=n; ++i)if(!vis[i]) { 14 ++ret; 15 for(int j=i; !vis[j]; j=c[j])vis[j]=1; 16 } 17 return ret; 18 } 19 20 int main() { 21 while(scanf("%d",&n)&&n) { 22 ans=inf; 23 for(int i=1; i<=n; ++i)scanf("%d",&a[i]); 24 for(int i=1; i<=n; ++i)b[i]=i; 25 do { 26 ans=min(ans,n-cir(a,b,n)); 27 for(int i=1; i<n; ++i)swap(b[i],b[i+1]); 28 } while(b[1]!=1); 29 for(int i=1; i<=n; ++i)b[i]=n-i+1; 30 do { 31 ans=min(ans,n-cir(a,b,n)); 32 for(int i=1; i<n; ++i)swap(b[i],b[i+1]); 33 } while(b[1]!=n); 34 printf("%d\n",ans); 35 } 36 return 0; 37 }
原文地址:https://www.cnblogs.com/asdfsag/p/10354061.html
时间: 2024-11-10 16:41:45