zoukankan      html  css  js  c++  java
  • HDU 1394 Minimum Inversion Number(归并排序 线段树 逆序数)

    http://acm.hdu.edu.cn/showproblem.php?pid=1394

    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个从0到n 的数 按照给定次序排列 每次只能将最前的一个数移到末尾 算出每种情况的逆序数 并求出逆序数最小值

    思路:

    归并排序或线段树

    首先 我们把当前情况下的逆序数求出

    然后循环n次 每次最前一个往最后移 则 ans=ans+ (n-1+a[i])-a[i]

    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    int num[5000+10],a[5000+10],t[5000+10];
    //int vis[5000+10];
    int ans;
    
    void Merge(int x,int m,int y)
    {
        int p=x,q=m+1,i=x;
        while(p<=m||q<=y)
        {
            if(q>y||(p<=m&&a[p]<=a[q])) t[i++]=a[p++];
            else
            {
                t[i++]=a[q++];
                ans+=m-p+1;
            }
        }
        for(i=x;i<=y;i++) a[i]=t[i];
    }
    void mergesort(int x,int y)
    {
       if(x!=y)
       {
           int mid=(x+y)/2;
           mergesort(x,mid);
           mergesort(mid+1,y);
           Merge(x,mid,y);
       }
    }
    int main()
    {
        int n,i,j,minn;
        while(scanf("%d",&n)!=EOF)
        {
          ans=0;
          for(i=1;i<=n;i++)
            {scanf("%d",&a[i]); num[i]=a[i];}
          mergesort(1,n);
          minn=ans;
          for(i=1;i<n;i++)
          {
              ans=ans+n-1-2*num[i];
              if(ans<minn) minn=ans;
          }
          cout<<minn<<endl;
        }
        return 0;
    }
    

      

      

    线段树的版本 

    对于初始序列

    每次加入一个数就对其标记 并且查询是否有比他大的数已经被加入 从而求出逆序数

    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #include<stack>
    #define mem(a,b) memset(a,b,sizeof(a))
    #define ll __int64
    #define MAXN 1000
    #define INF 0x7ffffff
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    using namespace std;
    int sum[50000];
    int a[5000+10];
    void pushup(int rt)
    {
        sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    }
    void build(int l,int r,int rt)
    {
        if(l==r)
        {
            sum[rt]=0; return ;
        }
        int m=(l+r)>>1;
        build(lson);
        build(rson);
        pushup(rt);
    }
    int getnum(int L,int R,int l,int r,int rt)
    {
        if(L<=l&&r<=R)
        {
    
            return sum[rt];
        }
        int ret=0;
        int m=(l+r)>>1;
        if(L<=m) ret+=getnum(L,R,lson);
        if(R>m)  ret+=getnum(L,R,rson);
        return ret;
    }
    void update(int num,int l,int r,int rt)
    {   
        if(l==r&&l==num)
        {       
            sum[rt]=1;
            return ;
        }    
        int m=(l+r)>>1;   
        if(num<=m) update(num,lson);
        else       update(num,rson);
        pushup(rt);
    }
    int main()
    {
        int n;
        int i,j;
        int ans,minn;
        while(scanf("%d",&n)!=EOF)
        {
            ans=0;
            build(0,n-1,1);
            for(i=0;i<n;i++)
            {
                scanf("%d",&a[i]);
                ans+=getnum(a[i],n-1,0,n-1,1);          
                update(a[i],0,n-1,1);
            }
            minn=ans;       
            for(i=0;i<n-1;i++)
            {
                ans=ans-a[i]*2+n-1;
                if(minn>ans) minn=ans;
            }
            cout<<minn<<endl;
        }
        return 0;
    }
    

      

  • 相关阅读:
    软件大赛excel转换
    迷你表单美化框架 Ideal Forms
    FLV播放器代码 网页FLV在线播放代码
    网站被降权了该怎么办
    jQuery弹出层插件bPopup
    如何去增加外部链接
    IIS MIME设置
    jQuery无缝滚动
    jQuery表单验证插件 jQuery validate
    dedecms实现关键字自动加内链
  • 原文地址:https://www.cnblogs.com/sola1994/p/3901536.html
Copyright © 2011-2022 走看看