zoukankan      html  css  js  c++  java
  • HDU 1394 Minimum Inversion Number (线段树&&暴力)

    Minimum Inversion Number

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


    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
     
    Author
    CHEN, Gaoli
     
    Source
     
    Recommend
    Ignatius.L
     
     
    题目的意思就是说给你一个序列,求这个序列的逆序数的对数,然后将第一个元素放到最后,从而生成了一个新的序列,直到最后一个元素到第一个时停止,求生成的序列中,最少的逆序数的对数是多少。
     
    我谈谈我的做法
    1.暴力,每次找出新序列的逆序数的对数,然后看看是不是最小值,最后输出最小值即可
    但这里要点技巧,在寻找新的序列的逆序数的对数时,没有必要去扫一遍出结果。
    可以想想,因为序列的数字是从0~n-1连续的,那么当第一个数移到最后去的时候,原来比这个数大的数字变成了逆序数,比这个数小的数就不是逆序数了
    举个例子:
    3 2 4 5 
    本来 3 2是逆序数,3 4,3 5不是逆序数,当序列变成2 4 5 3时,原来的3 4变成了4 3是逆序数,2 3就不是逆序数了
     
    所以在原有的序列中比第一个元素要小的数个数为(即逆序数的对数)  low[a[i]]=a[i],所以可以推出比第一个元素要大的数的个数为up[a[i]]=n-1-a[i]
    那么新的序列中逆序数的对数是  sum=sum-low[a[i]]+up[a[i]]=sum-a[i]+(n-1-a[i])
     
    暴力的代码
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<stdlib.h>
     4 #include<algorithm>
     5 using namespace std;
     6 int a[5005];
     7 int main()
     8 {
     9     int n,i,j;
    10     while(scanf("%d",&n)!=EOF)
    11     {
    12         int sum=0;
    13         for(i=0;i<n;i++)
    14         {
    15             scanf("%d",&a[i]);
    16             for(j=0;j<i;j++)
    17                 if(a[j]>a[i])
    18                     sum++;
    19         }
    20         int ans=sum;
    21         for(i=0;i<n;i++)
    22         {
    23             sum=sum-a[i]+(n-a[i]-1);
    24             if(sum<ans)
    25                 ans=sum;
    26         }
    27         printf("%d
    ",ans);
    28     }
    29     return 0;
    30 }
    View Code

    2.线段树

    同样的一开始也是要找出逆序数的对数,暴力方法是从第一个数到现在这个数扫一遍查找,线段树的方法就是用线段树去查询,会更快

    后面对新序列的逆序数对数的处理时相同的

    线段树的代码

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<stdlib.h>
     4 #include<algorithm>
     5 using namespace std;
     6 struct node
     7 {
     8     int l,r;
     9     int num;
    10     int mid()
    11     {
    12         return (l+r)>>1;
    13     }
    14 }a[5000*4];
    15 int b[5005];
    16 void btree(int l,int r,int step)
    17 {
    18     a[step].l=l;
    19     a[step].r=r;
    20     a[step].num=0;
    21     if(l==r)  return ;
    22     int mid=a[step].mid();
    23     btree(l,mid,step*2);
    24     btree(mid+1,r,step*2+1);
    25 }
    26 
    27 void ptree(int step,int vis)
    28 {
    29     a[step].num++;
    30     if(a[step].l==a[step].r)  return ;
    31     int mid=a[step].mid();
    32     if(vis>mid)
    33         ptree(step*2+1,vis);
    34     else
    35         ptree(step*2,vis);
    36 }
    37 
    38 int fintree(int step,int x,int y)
    39 {
    40     if(a[step].l==x&&a[step].r==y)
    41         return a[step].num;
    42     int mid=a[step].mid();
    43     if(x>mid)
    44         return fintree(step*2+1,x,y);
    45     else if(y<=mid)
    46         return fintree(step*2,x,y);
    47     else
    48         return fintree(step*2,x,mid)+fintree(step*2+1,mid+1,y);
    49 }
    50 int main()
    51 {
    52     int n,i,j;
    53     while(scanf("%d",&n)!=EOF)
    54     {
    55         int ans=0;
    56         btree(0,n-1,1);
    57         for(i=0;i<n;i++)
    58         {
    59             scanf("%d",&b[i]);
    60             ans+=fintree(1,b[i],n-1);
    61             ptree(1,b[i]);
    62         }
    63         int minn=ans;
    64         for(i=0;i<n;i++)
    65         {
    66             ans=ans-b[i]+(n-1-b[i]);
    67             if(minn>ans) minn=ans;
    68         }
    69         printf("%d
    ",minn);
    70     }
    71     return 0;
    72 }
    View Code
  • 相关阅读:
    《Machine Learning in Action》—— 白话贝叶斯,“恰瓜群众”应该恰好瓜还是恰坏瓜
    《Machine Learning in Action》—— 女同学问Taoye,KNN应该怎么玩才能通关
    《Machine Learning in Action》—— Taoye给你讲讲决策树到底是支什么“鬼”
    深度学习炼丹术 —— Taoye不讲码德,又水文了,居然写感知器这么简单的内容
    《Machine Learning in Action》—— 浅谈线性回归的那些事
    《Machine Learning in Action》—— 懂的都懂,不懂的也能懂。非线性支持向量机
    《Machine Learning in Action》—— hao朋友,快来玩啊,决策树呦
    《Machine Learning in Action》—— 剖析支持向量机,优化SMO
    《Machine Learning in Action》—— 剖析支持向量机,单手狂撕线性SVM
    JVM 字节码指令
  • 原文地址:https://www.cnblogs.com/clliff/p/3895053.html
Copyright © 2011-2022 走看看