hdu1394 Minimum Inversion Number(求逆序对)

Minimum Inversion Number

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 3466    Accepted Submission(s): 2113


Problem Description
The inversion number of a given number sequence a1, a2, ..., an is the number of pairs (ai, aj) that satisfy i < j and ai > aj.

For a given sequence of numbers a1, a2, ..., an, if we move the first m >= 0 numbers to the end of the seqence, we will obtain another sequence. There are totally n such sequences as the following:

a1, a2, ..., an-1, an (where m = 0 - the initial seqence)
a2, a3, ..., an, a1 (where m = 1)
a3, a4, ..., an, a1, a2 (where m = 2)
...
an, a1, a2, ..., an-1 (where m = n-1)

You are asked to write a program to find the minimum inversion number out of the above sequences.
 

 

Input
The input consists of a number of test cases. Each case consists of two lines: the first line contains a positive integer n (n <= 5000); the next line contains a permutation of the n integers from 0 to n-1.
 

 

Output
For each case, output the minimum inversion number on a single line.
 

 

Sample Input
10
1 3 6 9 0 8 5 7 4 2
Sample Output
16
 
题意:共有n-1个序列求最小的逆序对;
方法一:归并 O(n^2);
View Code
 1 #include<iostream>
 2 #define N 5010
 3 using namespace std;
 4 
 5 int A[N],B[N],T[N],ans;
 6 
 7 void merge(int s1,int e1,int s2,int e2)
 8 {
 9     int k,i,j;
10     k=i=s1;j=s2;
11     while(i<=e1&&j<=e2)
12     {
13         if(A[i]<=A[j])
14         {
15             T[k]=A[i];
16             k++;i++;
17         }
18         else
19         {
20             T[k]=A[j];
21             ans+=(e1-i+1);//i后面的肯定都大于A[j]
22             k++;j++;    
23         }
24     }
25     while(i<=e1)
26     {
27         T[k++]=A[i++];
28     }
29     while(j<=e2)
30     {
31         T[k++]=A[j++];
32     }
33     for(i=s1;i<=e2;i++) A[i]=T[i];
34 }
35 
36 void mergesort(int s,int e)
37 {
38     if(s<e)
39     {
40         int m=(s+e)>>1;
41         mergesort(s,m);
42         mergesort(m+1,e);
43         merge(s,m,m+1,e);
44     }
45 }
46 
47 int main()
48 {
49     int n,i,j,t,t1,t2,tt,ttt;
50     while(scanf("%d",&n)!=EOF)
51     {
52         ans=0;
53         for(i=0;i<n;i++)
54         {
55             scanf("%d",&A[i]);
56             B[i]=A[i];
57         }
58         mergesort(0,n-1);
59         tt=ans;
60         for(i=0;i<n-1;i++)
61         {
62             t1=t2=0;
63             t=B[0];
64             for(j=1;j<n;j++)
65             {
66                 B[j-1]=B[j];
67                 if(t<B[j])t1++;
68                 else if(t>B[j]) t2++;
69             }
70             tt=tt+t1-t2;
71             if(ans>tt) ans=tt;
72             B[n-1]=t;
73         }
74         printf("%d\n",ans);
75     }
76     return 0;
77 }

 

方法二:线段树实现(这也是做这题的原因)(模板)

1、离散化:把起初的元素用 0..n-1 这些数来替代,如2 5 2 6 离散化就是0 0 1 2,不过这个题不要离散化,而已每个元素都是不一样的 = =!!

          这样的话你就很快知道比s[i]大的数有多少,比s[i]小的数有多少。

2、每段树中区间 [tree[r].left,tree[r].right] 中有多少个以前出现过。

3、每次输入一个key ,就查找( key,n-1 ]中有多少个数以前出现过,再把 key 插入树中。

4、假设t是当前逆序对的个数,把s[0]移到最后产生的新序列的逆序对为 t+(n-1-s[0])-s[0];循环n-1次就能找到最小值了。

View Code
 1 #include<iostream>
 2 #define N 5010
 3 using namespace std;
 4 
 5 struct segtree
 6 {
 7     int left,right,sum;
 8 }tree[N<<2];
 9 int s[N];
10 
11 void build(int r,int a,int b)
12 {
13     tree[r].left=a;
14     tree[r].right=b;
15     tree[r].sum=0;
16     if(a<b)
17     {
18         int m=(a+b)>>1;
19         build(r<<1,a,m);
20         build(r<<1|1,m+1,b);
21     }
22 }
23 
24 /*
25 没考虑和a一样大的,也不存在
26 在插入a之前有多少(a,b]之间的数已经插入了,都是逆序对
27 */
28 int query(int r,int a,int b)
29 {
30     if(tree[r].left==a&&tree[r].right==b)
31         return tree[r].sum;
32     int m=(tree[r].left+tree[r].right)>>1;
33     if(b<=m) 
34         return query(r<<1,a,b);
35     else if(a>m)
36         return query(r<<1|1,a,b);
37     else 
38         return query(r<<1,a,m)+query(r<<1|1,m+1,b);
39 }
40 
41 void update(int r,int key)
42 {
43     tree[r].sum++;
44     if(tree[r].left==tree[r].right) return ;
45     int m;
46     m=(tree[r].left+tree[r].right)>>1;
47     if(key<=m) 
48         update(r<<1,key);
49     else
50         update(r<<1|1,key);
51 }
52 
53 int main()
54 {
55     int n,i,t,ans;
56     while(cin>>n)
57     {
58         ans=0;
59         build(1,0,n-1);
60         for(i=0;i<n;i++)
61         {
62             cin>>s[i];
63             ans+=query(1,s[i],n-1);
64             update(1,s[i]);
65         }
66         t=ans;
67         for(i=0;i<n-1;i++)
68         {
69             t=t+(n-1-s[i])-s[i];
70             if(ans>t)
71                 ans=t;
72         }
73         cout<<ans<<endl;
74     }
75     return 0;
76 }

 

posted @ 2012-05-16 09:00  mtry  阅读(567)  评论(0)    收藏  举报