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\n",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\n",sum); } return 0; }