HDU 1394

题意:给定一个序列,每次将第一个元素放至末尾,求其形成的所有序列中逆序数和最小;

可利用归并排序求出第一次的逆序数和,在用下面的公式求解最小的逆序数和;

当然此题暴力也可过。

如果每次都进行如上操作,那么最多进行n-1次后会与原序列重合;

这个序列的元素是从0---(n-1),当某个元素位于首位置时,其本身的数值就是后面的逆序个数;

每次将它移至末尾,原来的逆序即变成了正序,正序变逆;由此可得 sum=sum-a[i]+(n-a[i]-1);

//归并排序:
#include<stdio.h> #include<stdlib.h> #include<string.h> #define maxn 5010 #define Min(a,b)(a<b?a:b) int ac[maxn],ak[maxn],temp[maxn],ans; void merger(int *A,int s,int mid,int e) { int i,j,k=0; for(i=s,j=mid+1; i<=mid && j<=e;) { if(A[i] < A[j]) temp[k++]=A[i++]; else { ans+=mid-i+1; temp[k++]=A[j++]; } } while(i<=mid) temp[k++]=A[i++]; while(j<=e) temp[k++]=A[j++]; for(i=0; i<k; i++) A[s+i]=temp[i]; } void mergersort(int *A,int s,int e) { if(s<e) { int mid =(s+e)/2; mergersort(A,s,mid); mergersort(A,mid+1,e); merger(A,s,mid,e); } } int main() { int n,i,sum; while(~scanf("%d",&n)) { for(i=0; i<n; i++) { scanf("%d",&ac[i]); ak[i]=ac[i]; } ans=0; mergersort(ac,0,n-1); sum=ans; for(i=0; i<n; i++) { sum=sum-ak[i]+(n-ak[i]-1); ans=Min(sum,ans); } printf("%d ",ans); } return 0; }
//暴力解决:
#include<stdio.h> int a[5005]; int main() { int n,i,j,ans,sum; while(~scanf("%d",&n)) { for(i=0; i<n; i++) scanf("%d",&a[i]); ans = 0; sum=999999999; for(i=0; i<n; i++) for(j=i+1; j<n; j++) if(a[i]>a[j]) ans++; if(ans < sum) sum =ans; for(i=0; i<n; i++) { ans = ans -a[i] +(n-1-a[i]); if(ans < sum) sum =ans; } printf("%d ",sum); } return 0; }
原文地址:https://www.cnblogs.com/cn-blog-cn/p/4712489.html