HDU 5122

K.Bro Sorting

Time Limit: 2000/2000 MS (Java/Others)    Memory Limit: 512000/512000 K (Java/Others)
Total Submission(s): 299    Accepted Submission(s): 171


Problem Description
Matt’s friend K.Bro is an ACMer.

Yesterday, K.Bro learnt an algorithm: Bubble sort. Bubble sort will compare each pair of adjacent items and swap them if they are in the wrong order. The process repeats until no swap is needed.

Today, K.Bro comes up with a new algorithm and names it K.Bro Sorting.

There are many rounds in K.Bro Sorting. For each round, K.Bro chooses a number, and keeps swapping it with its next number while the next number is less than it. For example, if the sequence is “1 4 3 2 5”, and K.Bro chooses “4”, he will get “1 3 2 4 5” after this round. K.Bro Sorting is similar to Bubble sort, but it’s a randomized algorithm because K.Bro will choose a random number at the beginning of each round. K.Bro wants to know that, for a given sequence, how many rounds are needed to sort this sequence in the best situation. In other words, you should answer the minimal number of rounds needed to sort the sequence into ascending order. To simplify the problem, K.Bro promises that the sequence is a permutation of 1, 2, . . . , N .
 

Input
The first line contains only one integer T (T ≤ 200), which indicates the number of test cases. For each test case, the first line contains an integer N (1 ≤ N ≤ 10 6).

The second line contains N integers a i (1 ≤ a i ≤ N ), denoting the sequence K.Bro gives you.

The sum of N in all test cases would not exceed 3 × 10 6.
 

Output
For each test case, output a single line “Case #x: y”, where x is the case number (starting from 1), y is the minimal number of rounds needed to sort the sequence.
 

Sample Input
  
  
2 5 5 4 3 2 1 5 5 1 2 3 4
 

Sample Output
  
  
Case #1: 4 Case #2: 1
Hint
In the second sample, we choose “5” so that after the first round, sequence becomes “1 2 3 4 5”, and the algorithm completes.
 

Source
 


题意:

给你n个数字,问你最少操作多少次使得这个序列成上升序列。操作:随机选一个数与相邻后面的一个数比较,如果比后面那个小,则与其交换,否则停止此次操作。


分析:

如果是手动模拟的话,最少操作多少次应该每次选没被操作过的最大的数字,这样就可操作次数最少。纯模拟肯定超时,于是换种思维,可以计算每个数字前面有多少个大于它且没有被交换的数字,利用二分即可,时间复杂度为nlog(n)。


程序如下:

#include<stdio.h>
#include<algorithm>
using namespace std;
int a, b[1000010];
int main()
{
    int T, n, t=1;

    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &n);
        int index = 0, cnt = 0, sum = 0;
        for(int i=0; i<n; i++)
        {
            scanf("%d", &a);
            index = (lower_bound(b,b+cnt,a)-b);
            b[index] = a;
            sum += cnt-index;
            cnt = index+1;
        }
        printf("Case #%d: %d\n", t++,sum);
    }
    return 0;
}

终于AC后,想想自己的方法似乎实现起来还是有点麻烦的,于是就看了下别人是怎么写的,果然比我的简单很多啊:

从后往前遍历,如果这个数比后面那个数大,操作数就加1并且交换。因为从后往前遍历的话,那个数身后的那个数一定是后面序列中最小的数,此时就可判断是否需要进行操作。其实这种方法的主要思想就是判断每一位数是否需要进行操作,操作的理由就是后面是否有比它小的数,由于一个数只能往后走,所以当后面有比它小的数的话就一定需要操作,并且操作数最小为1。

#include<stdio.h>
#include<algorithm>
using namespace std;
int a[1000010];
int main()
{
    int T, n, t=1;

    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &n);
        for(int i=1; i<=n; i++)
            scanf("%d", a+i);
        int sum = 0;
        for(int i=n-1; i>=1; i--)
        {
            if(a[i] > a[i+1])
                sum++, swap(a[i],a[i+1]);
        }
        printf("Case #%d: %d\n", t++,sum);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值