您的位置:首页 > 其它

Hdu 1394-Minimum Inversion Number【暴力求解Or线段树Or树状数组】

2015-07-12 18:03 369 查看


Minimum Inversion Number

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)

Total Submission(s): 13357 Accepted Submission(s): 8167



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
[code]//暴力求解 时间就不说了吧
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 5000+5;
int N,arr[maxn];
int main() {
  //  freopen("input.in","r",stdin);
    while(~scanf("%d",&N)) {
        for(int i = 0;i < N;i++) {
            scanf("%d",&arr[i]);
        }
        int ans,cnt=0;
        for(int i = 0;i < N;i++) {
            for(int j = i+1;j < N;j++) {
                if(arr[i]>arr[j]) cnt++;
            }
        }
        ans = cnt;
        for(int i = 0;i < N;i++) {
            cnt = cnt+(N-1-arr[i])-arr[i];//找出规律,每次将最前面的数移至末尾,大于arr[i]的数为(N-1-arr[i]),小于arr[i]的数为arr[i].
            ans = min(ans,cnt);
        }
        printf("%d\n",ans);
    }
    return 0;
}

//树状数组:46ms[/code]
#include <map>
#include <cmath>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int maxn = 5000+5;
int N,ans,arr[maxn],TreeArr[maxn];
int lowbit(int x) { return x&(-x); }
void Add(int pos,int add=1) {
    while(pos <= N) {
        TreeArr[pos] += add;
        pos+=lowbit(pos);
    }
}
int Sum(int pos) {
    int ret = 0;
    while(pos > 0) {
        ret+=TreeArr[pos];
        pos -= lowbit(pos);
    }
    return ret;
}
int main() {
    //freopen("input.in","r",stdin);
    while(~scanf("%d",&N)) {
        ans = 0;memset(TreeArr,0,sizeof(TreeArr));
        for(int i = 1;i <= N;i++) {
            scanf("%d",&arr[i]);arr[i]++;   //将每个数加一,这样就把数控制在1~N范围,貌似看起来舒服些
            ans += Sum(N)-Sum(arr[i]);      //将之前的数中在区间arr[i]~N的个数进行累加
            Add(arr[i]);
        }
        for(int i = 1,cnt = ans;i <= N;i++) {
            cnt += (N-arr[i])-arr[i]+1;
            ans = min(ans,cnt);
        }
        printf("%d\n",ans);
    }
    return 0;
}
//线段树 93ms
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int maxn = 5000+5;
int N,ans,arr[maxn],segTree[maxn<<2];
void PushUp(int rt) { segTree[rt] = segTree[rt<<1] + segTree[rt<<1|1]; }
void Build(int l,int r,int rt) {
    segTree[rt] = 0;
    if(l == r) return ;
    int mid = l+((r-l)>>1);
    Build(lson);
    Build(rson);
}
void Update(int pos,int l,int r,int rt) {
    if(l == r) {
        segTree[rt]++;
        return ;
    }
    int mid = l+((r-l)>>1);
    if(pos<=mid) Update(pos,lson);
    else Update(pos,rson);
    PushUp(rt);
}
int Query(const int &L,const int &R,int l,int r,int rt) {
    if(L<=l&&r<=R) {
        return segTree[rt];
    }
    int mid = l+((r-l)>>1),ret = 0;
    if(L<=mid) ret+=Query(L,R,lson);
    if(R>mid) ret+=Query(L,R,rson);
    return ret;
}
int main() {
   // freopen("input.in","r",stdin);
    while(~scanf("%d",&N)) {
        ans = 0;Build(1,N,1);
        for(int i = 0;i < N;i++) {
            scanf("%d",&arr[i]);arr[i]++;      //将每个数加一,这样就把数控制在1~N范围,貌似看起来舒服些
            if(arr[i] != N)
                ans += Query(arr[i]+1,N,1,N,1);      //将之前的数中在区间arr[i]+1~N的个数进行累加
            Update(arr[i],1,N,1);
        }
        for(int i = 0,cnt = ans;i < N;i++) {
            cnt += (N-arr[i])-arr[i]+1;
            ans = min(ans,cnt);
        }
        printf("%d\n",ans);
    }
    return 0;
}
当然,我还在网上看到了有用归并排序模板过的,这里就不累赘了!转载请注明出处,谢谢!~



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: