洛谷P1327 数列排序
数学 图论
这道题其实 就是求 排序前以及排序后的连通块 冲突减连边 ,因为交换的都是在那个连通块中的,这样就能保证最优
这样连通块中有 n 个点,就是要交换 n-1 次
但是 我写的常数 非常丑 结果洛谷上T了一个点 开心
将序列排序
找出所有的循环,即错误位置调换的循环
如 2 4 1 3 循环为 2->4->3->1->2
(手写快排累死了)
代码 (减少代码复制,创建美好洛谷)
1 #include <cstdio> // 90 分 2 #include <algorithm> 3 #include <map> 4 using namespace std ; 5 6 const int maxn = 100011,inf = 1000 ; 7 int n,ans ; 8 int a[maxn],b[maxn] ; 9 map <int,bool> f ; 10 11 inline int dfs(int u) 12 { 13 int sum = 1 ; 14 int x = 0,y = 0 ; 15 if( f.count(a[ u ]) ) return 0 ; 16 f[ a[ u ] ] = 1 ; 17 while(1) 18 { 19 x = a[ u ] ; 20 u = lower_bound(b+1,b+n+1,x) - b ; 21 if( f.count(a[ u ]) ) break ; 22 sum++ ; 23 f[ a[ u ] ] = 1 ; 24 } 25 return sum - 1 ; 26 27 } 28 29 int main() 30 { 31 scanf("%d",&n) ; 32 for(int i=1;i<=n;i++) scanf("%d",&a[ i ]),b[ i ] = a[ i ] ; 33 sort(b+1,b+n+1) ; 34 for(int i=1;i<=n;i++) 35 if(a[ i ]==b[ i ]) continue ; 36 else ans+=dfs( i ) ; 37 printf("%d",ans) ; 38 39 return 0 ; 40 }
代码的优化
1、将对值的布尔转成对 原来下标的布尔 ,这样少掉一只map
2、快排时直接处理 快排前与快排后 少掉 二分 lower_bound
3、手打快排 优化常数
这样优化了之后就能 过了
1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 int n,a[100001],b[100001],ans,x,tot; // ac 程序 5 bool flag[100001]; 6 void kp(int l,int r) 7 { 8 int i=l,j=r,x,t; 9 x=a[(i+j)/2]; 10 while(i<=j) 11 { 12 while (a[i]<x) i++; 13 while (a[j]>x) j--; 14 if (i<=j) 15 {t=a[i];a[i]=a[j];a[j]=t; 16 t=b[i];b[i]=b[j];b[j]=t;i++;j--;} 17 } 18 if (l<j) kp(l,j); 19 if (i<r) kp(i,r); 20 } 21 int main() 22 { 23 memset(flag,false,sizeof(flag)); 24 cin >> n; 25 for(int o=1;o<=n;o++) 26 { 27 cin >> a[o]; 28 b[o]=o; 29 } 30 kp(1,n); 31 for(int i=1;i<=n;i++) 32 if(!flag[i]) 33 { 34 x=i;tot=0; 35 while(!flag[x]) 36 { 37 flag[x]=true; 38 tot++; 39 x=b[x]; 40 } 41 ans+=tot-1; 42 } 43 cout << ans; 44 return 0; 45 }