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
2014ACM/ICPC亚洲区北京站-重现赛(感谢北师和上交)
题意:
给你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;
}