Sorting a Three-Valued Sequence (模拟)
Description
排序是一种很频繁的计算任务。现在考虑最多只有三值的排序问题。一个实际的例子是,当我们给某项竞赛的优胜者按金银铜牌序的时候。 在这个任务中可能的值只有三种1,2和3。我们用交换的方法把他排成升序的。 写一个程序计算出,给定的一个1,2,3组成的数字序列,排成升序所需的最少交换次数。
Input
Line 1: N (1 <= N <= 1000) Lines 2-N+1: 每行一个数字,共N行。(1..3)
Output
共一行,一个数字。表示排成升序所需的最少交换次数。
Sample Input
9 2 2 1 3 3 3 2 3 1
Sample Output
4
虽然师兄们把这个当成了一个贪心题,但是我觉得还是应该当成模拟来看。。。。
求的就是最少的次数,那么对于任意的三个数,当我们需要把他们放到应该放的位置上的时候,
有且只有三种情况
1.三个数都不在自己的位置上,例如位置为1,2,3但是三个数的顺序为2,3,1.这时候我们需要进行2次调换
才能让1,2,3在自己的位置上,也就是付出2次操作的代价换来了3个数字归位
2.三个数中只有一个数在自己的位置上,例如位置为1,2,3,但是三个数字的顺序为3,2,1,。这时候我们需要调换1和3才能使三个数归位,也就是付出了1次操作的代价换来了2个相互调换位置的数归位
3.三个数都在自己位置上,这时候不需要进行操作
所以我们需要做的是:先找出情况2的次数(因为让两数归位不会影响情况1),然后找出情况1的次数
设c12为数组c中1区域中含有2的数目,则同理设出c21,c13,c31,c23,c32;
然后设cnt为没有在自己位置上的数字的数目;
则需要进行2操作的次数为:ans1 = min(cn12,cn21)+min(cn13,cn31)+min(cn23,cn32);
进行三操作的次数为:ans2 = (cnt - ans*2 )*2/3 ///进行2操作后剩下的次数乘以2/3即进行3操作的次数
所以答案为ans = ans2+ans1;
代码如下
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
#define For(i,n) for(int i=0;i<n;i++)
#define mem(a) memset(a,0,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn = 1e4+2;
ll a[maxn],b[maxn];
int main() {
ll r1,r2;
ll n,i;
ll cnt;
cin >> n;
cnt = 0;
mem(a);
mem(b);
For(i,n) {
cin >> a[i];
b[i] = a[i];
}
sort(b,b+n);
for(i=1; i<n; i++) {
if(b[i-1]==1&&b[i]==2)
r1 = i;
if(b[i-1]==2&&b[i]==3)
r2 = i;
}
ll cn12,cn31,cn21,cn23,cn13,cn32;
cn31 = cn21 = cn23 = cn12 = cn13=cn32=0;
for(i=0; i<n; i++) {
if(i>=r1&&i<r2) {
if(a[i]==1)
cn21++,cnt++;
else if(a[i]==3)
cn23++,cnt++;
}
else if(i>=r2) {
if(a[i]==1)
cn31++,cnt++;
if(a[i]==2)
cn32++,cnt++;
}
else {
if(a[i]==2)
cn12++,cnt++;
if(a[i]==3)
cn13++,cnt++;
}
}
ll ans = min(cn12,cn21)+min(cn23,cn32)+min(cn13,cn31);
ans += (cnt-ans*2)/3*2;
cout << ans<<endl;
return 0;
}