USACO section 2.1 Sorting a Three-Valued Sequence

Sorting a Three-Valued Sequence
IOI'96 - Day 2

Sorting is one of the most frequently performed computational tasks. Consider the special sorting problem in which the records to be sorted have at most three different key values. This happens for instance when we sort medalists of a competition according to medal value, that is, gold medalists come first, followed by silver, and bronze medalists come last.

In this task the possible key values are the integers 1, 2 and 3. The required sorting order is non-decreasing. However, sorting has to be accomplished by a sequence of exchange operations. An exchange operation, defined by two position numbers p and q, exchanges the elements in positions p and q.

You are given a sequence of key values. Write a program that computes the minimal number of exchange operations that are necessary to make the sequence sorted.

PROGRAM NAME: sort3

INPUT FORMAT

Line 1:N (1 <= N <= 1000), the number of records to be sorted
Lines 2-N+1:A single integer from the set {1, 2, 3}

SAMPLE INPUT (file sort3.in)

9
2
2
1
3
3
3
2
3
1

OUTPUT FORMAT

A single line containing the number of exchanges required

SAMPLE OUTPUT (file sort3.out)

4

 

这题A的很冤,整整交了四次,是目前为止交的次数最多的了

解题思路:因为只有1,2,3,所以只要记录s存1,2,3所出现的次数,把其分为1,2,3三个区间,然后遍历1的区间,找到非1 的数,然后遍历这个数的区间去找1

若没有,则把任意一个非此区间的数与之交换。当1区间均为1时,只要在遍历2 的区间找到非2 的数的个数于前面的交换次数相加即为答案

 

 

 

/*
ID:nealgav1
PROG:sort3
LANG:C++
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1005
using namespace std;
int f[N];
int s[4];
void swapp(int&a,int &b)
{int z;
  z=a;a=b;b=z;
}
int qqsort(int n)
{
  int l=0,mid=s[1]+1,r=s[1]+s[2]+1;
  int i,j,ans=0;
  while(1)
  {
    for(i=l+1;i<=s[1];i++)
    {
      if(f[i]!=1)break;l++;
    }
    if(l==s[1])break;
    if(f[i]==2)
     { bool flag=0,ff=1;
      for(j=mid;j<=s[1]+s[2];j++)
      {
        if(f[j]!=2&&ff)mid=j,ff=0;
        if(f[j]==1){swapp(f[j],f[i]),ans++;flag=1;break;}
      }
        if(!flag)
        for(j=mid;j<=s[1]+s[2];j++)
        if(f[j]==3){swapp(f[j],f[i]),ans++;break;}
     }
    else
    {
      bool sss=0,ss=1;
      for(j=r;j<=n;j++)
      {if(f[j]!=3&&ss)
         { r=j;ss=0;}
        if(f[j]==1)
         {swapp(f[j],f[i]),ans++;sss=1;break;}
      }
      if(!sss)
      for(j=r;j<=n;j++)
      if(f[j]==2){swapp(f[j],f[i]);ans++;break;}
    }
  }
  for(i=s[1]+1;i<=s[2]+s[1];i++)
  if(f[i]==3)ans++;
  return ans;
}
int main()
{
  int n;
  freopen("sort3.in","r",stdin);
  freopen("sort3.out","w",stdout);
  scanf("%d",&n);
  s[1]=s[2]=s[3]=0;
  for(int i=1;i<=n;i++)
  {
    scanf("%d",&f[i]);s[f[i]]++;
  }
   printf("%d\n",qqsort(n));
}


 

 

 

 

Sorting A Three-Valued Sequence
Russ Cox

We read the input into an array, and sort a copy of it in another array, so we know what we have and what we want.

A swap touches two elements, so it can correct at most two misplaced elements. We run through the array looking for pairs of misplaced elements that a swap would correct, and do those swaps.

The remaining misplaced elements form little cycles: a 1 where a 2 should be, a 2 where a 3 should be, and that 3 where the 1 should be. It takes two swaps to correct such a cycle. So we count the number of such cycles (by counting misplaced elements and dividing by three) and then add in two times that many swaps.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#define MAXN 	1000

int n;
int have[MAXN];
int want[MAXN];

int
intcmp(const void *a, const void *b)
{
    return *(int*)a - *(int*)b;
}

void
main(void)
{
    int i, j, k, n, nn[4], nswap, nbad;
    FILE *fin, *fout;

    fin = fopen("sort3.in", "r");
    fout = fopen("sort3.out", "w");
    assert(fin != NULL && fout != NULL);

    fscanf(fin, "%d", &n);

    for(i=0; i<n; i++) {
	fscanf(fin, "%d", &have[i]);
	want[i] = have[i];
    }
    qsort(want, n, sizeof(want[0]), intcmp);

    /* swaps that correct two elements */
    nswap = 0;
    for(i=0; i<n; i++)
    for(j=0; j<n; j++) {
	if(have[i] != want[i] && have[j] != want[j]
	        && have[i] == want[j] && have[j] == want[i]) {
	    have[i] = want[i];
	    have[j] = want[j];
	    nswap++;
	}
    }

    /* remainder are pairs of swaps that correct three elements */
    nbad = 0;
    for(i=0; i<n; i++)
	if(have[i] != want[i])
	    nbad++;

    assert(nbad%3 == 0);
    nswap += nbad/3 * 2;

    fprintf(fout, "%d\n", nswap);
    exit(0);
}

Dan Jasper from Germany writes:

The previous solution needs a copy of the original list and O(N2) time. I think it was necessary with the original task, where you had to print out the exchange operations, but to just count them, there is a more efficient solution. You can count the "1", "2" and "3", so you can calculate in what parts (buckets) of the list they have to be. The rest of the solution is somehow equal to yours, but all in all it uses O(N) time and does not need a copy of the list.

#include <stdio.h>

int list[1000], N, res, count[3], start[3];
in[3][3]; // this counts the number of "1"s in bucket "2", ...

void readFile() {
    FILE *f; int i;
    f = fopen("sort3.in", "r");
    fscanf(f, "%d", &N);
    for(i = 0; i < N; i++) {
        fscanf(f, "%d", &list[i]);
    }
    fclose(f);
}

void writeFile() {
    FILE *f;
    f = fopen("sort3.out", "w");
    fprintf(f, "%d\n", res);
    fclose(f);
}

void findBuckets() {
    int i;
    for(i = 0; i < N; i++) count[list[i]-1]++;
    start[0] = 0;
    start[1] = count[0];
    start[2] = count[0] + count[1];
}

void findWhere() {
    int i, j;
    for(i = 0; i < 3; i++) {
        for(j = 0; j < count[i]; j++) in[list[start[i] + j]-1][i]++;
    }
   }

void sort() {
    int h;
    // 1 <-> 2
    h = in[0][1];
    if(in[1][0] < h) h = in[1][0];
    res += h; in[0][1] -= h; in[1][0] -= h;
    // 3 <-> 2
    h = in[2][1];
    if(in[1][2] < h) h = in[1][2];
    res += h; in[2][1] -= h; in[1][2] -= h;
    // 1 <-> 3
    h = in[0][2];
    if(in[2][0] < h) h = in[2][0];
    res += h; in[0][2] -= h; in[2][0] -= h;

    // Cycles
    res += (in[0][1] + in[0][2]) * 2;
}

void process() {
    findBuckets();
    findWhere();
    sort();
}

int main () {
    readFile();
    process();
    writeFile();
    return 0;
}

Bulgaria's Evgeni Dzhelyov writes:

I read the elements one by one and count them, so we know exactly how 1s, 2s and 3s we have and we know how the sorted array looks like. Then I count the 2s in 1 and 1s in 2, so it is obvious that we need min(2sin1, 1sin2) swaps, I do the same for 1-3 and 2-3. The sum of all these mins give us the number of direct swaps we need. After that number of swaps we would have N 1s, 2s and 3s and we would need 2*N swaps, where N is max(2sin1, 1sin2) - min(2sin1, 1sin2).

Here is the source code:

#include <fstream>

using namespace std;

int min (int a, int b) { return a < b ? a : b; }
int max (int a, int b) { return a > b ? a : b; }

int main () {
    int s[1024];
    int n;
    int sc[4] = {0};
    
    ifstream fin("sort3.in");
    ofstream fout("sort3.out");
    fin>>n;
    for (int i = 0; i < n; i++) {
        fin>>s[i];
        sc[s[i]]++;
    }
    int s12 = 0, s13 = 0, s21 = 0, s31 = 0, s23 = 0, s32 = 0;
    for (int i = 0; i < sc[1]; i++){
        if (s[i] == 2) s12++;
        if (s[i] == 3) s13++;
    }
    
    for (int i = sc[1]; i < sc[1]+sc[2]; i++){
        if (s[i] == 1) s21++;
        if (s[i] == 3) s23++;
    }
    
    for (int i = sc[1]+sc[2]; i < sc[1]+sc[2]+sc[3]; i++){
        if (s[i] == 1) s31++;
        if (s[i] == 2) s32++;
    }
    
    fout<<min(s12, s21)+min(s13, s31)+min(s23, s32) +
					2*(max(s12, s21) - min(s12, s21))<<endl;
    return 0;
}


 

 

USER: Neal Gavin Gavin [nealgav1]
TASK: sort3
LANG: C++

Compiling...
Compile: OK

Executing...
   Test 1: TEST OK [0.000 secs, 3348 KB]
   Test 2: TEST OK [0.000 secs, 3348 KB]
   Test 3: TEST OK [0.000 secs, 3348 KB]
   Test 4: TEST OK [0.011 secs, 3348 KB]
   Test 5: TEST OK [0.000 secs, 3348 KB]
   Test 6: TEST OK [0.000 secs, 3348 KB]
   Test 7: TEST OK [0.000 secs, 3348 KB]
   Test 8: TEST OK [0.000 secs, 3348 KB]

All tests OK.

Your program ('sort3') produced all correct answers! This is your submission #5 for this problem. Congratulations!

Here are the test data inputs:

------- test 1 ----
3
2
1
3
------- test 2 ----
2
1
1
------- test 3 ----
6
1
2
3
2
3
1
------- test 4 ----
9
2
2
1
3
3
3
2
3
1
------- test 5 ----
20
1
1
3
2
1
1
1
3
2
1
3
3
2
1
3
1
1
2
3
1
------- test 6 ----
50
1
1
1
3
1
3
2
1
2
3
3
1
3
2
1
1
2
3
2
2
3
3
2
3
2
2
3
1
1
1
1
1
1
1
3
1
1
2
2
3
1
1
3
3
2
1
1
1
3
2
------- test 7 ----
100
3
2
2
3
1
2
2
2
1
2
2
3
2
3
2
2
3
3
2
2
2
3
3
3
3
2
2
1
2
2
1
1
1
3
1
1
2
2
3
3
1
1
2
2
1
1
3
1
3
1
3
2
1
2
1
3
3
3
1
2
1
1
2
1
3
2
2
1
1
1
3
1
2
2
3
3
2
3
3
2
1
2
3
1
3
1
1
3
3
1
1
1
1
3
1
1
2
3
1
2
------- test 8 ----
1000
3
1
3
2
1
1
3
3
2
1
3
2
3
2
3
2
3
2
1
1
3
3
3
2
1
1
2
3
2
2
1
1
3
1
3
1
1
2
3
3
3
3
2
3
2
1
2
1
3
2
1
2
2
1
1
3
1
3
3
3
1
1
1
1
1
3
2
1
2
2
3
2
1
2
1
3
2
3
3
2
2
1
1
3
1
1
3
2
3
2
2
1
3
2
2
3
1
3
1
2
1
1
1
2
2
1
2
1
3
1
2
1
1
2
1
2
3
1
1
3
2
2
1
2
1
2
1
1
2
2
3
3
2
3
2
1
1
3
1
1
3
3
2
1
2
2
3
1
2
3
3
1
2
3
2
2
2
3
3
3
1
3
2
3
3
3
3
1
2
1
1
2
3
2
2
1
1
2
2
3
2
2
3
3
2
2
2
3
1
2
3
2
2
1
1
1
1
3
2
3
1
2
1
3
1
3
1
1
1
2
3
3
3
3
2
1
2
1
1
2
3
3
3
1
1
1
2
2
1
3
1
1
2
2
3
2
2
1
3
3
2
3
2
2
3
1
3
1
1
3
3
3
3
2
1
1
3
2
2
3
2
2
3
3
1
3
1
2
3
3
1
2
3
2
3
2
2
2
2
3
2
1
3
1
3
3
1
2
2
3
1
3
2
1
2
2
3
3
3
3
3
1
1
2
3
3
3
2
2
2
1
3
2
1
1
1
1
2
3
2
1
1
2
2
1
1
3
1
3
3
3
3
3
3
1
3
3
1
1
1
2
1
1
3
1
1
1
1
3
3
3
3
3
1
2
1
1
1
1
1
1
3
3
1
3
1
3
2
2
3
3
3
1
3
3
1
1
1
2
3
1
2
3
3
3
1
1
3
2
1
1
2
1
1
2
3
2
2
2
3
1
2
3
1
2
3
2
2
3
1
1
3
2
1
3
1
1
3
1
2
1
2
3
1
2
2
1
1
3
2
3
1
1
3
1
2
2
3
3
2
3
1
1
2
1
1
3
2
3
3
3
3
2
3
1
1
1
1
1
1
3
1
1
3
3
2
1
1
2
1
2
1
2
3
3
3
3
2
1
3
2
3
3
3
2
3
3
3
1
3
1
3
3
1
2
2
3
3
3
1
1
2
2
3
1
1
2
1
2
2
3
3
2
3
3
1
2
2
3
3
2
3
2
1
1
1
3
1
1
3
1
1
1
2
3
1
3
2
2
2
1
1
1
2
1
1
3
3
2
2
2
3
2
3
1
3
3
1
3
1
3
1
1
1
3
1
2
2
3
3
3
3
1
1
1
1
1
3
3
3
2
1
3
1
3
3
1
3
1
3
3
1
1
1
1
3
2
2
2
1
2
1
3
2
2
1
2
2
1
1
2
3
2
1
3
2
1
3
2
1
3
2
1
3
2
2
2
1
3
3
1
1
1
1
3
3
1
1
2
1
2
3
1
1
3
3
2
3
3
3
1
3
1
1
2
3
3
1
3
2
1
3
3
2
3
2
1
1
3
2
2
2
1
2
2
1
2
3
3
1
3
1
3
1
2
2
3
1
3
2
3
3
2
3
2
2
2
2
2
1
3
1
2
1
2
1
1
3
1
1
1
3
1
1
3
3
2
3
3
2
2
2
1
1
1
2
2
2
1
1
3
1
1
2
2
3
2
3
2
2
3
3
2
1
3
2
3
2
1
3
3
2
1
1
2
2
3
1
1
3
2
3
1
2
1
2
1
3
1
3
2
1
2
3
2
1
2
1
3
2
1
2
1
1
2
3
3
1
1
3
1
2
2
1
3
3
2
1
2
2
1
1
3
2
3
1
3
1
2
2
3
2
3
1
2
2
1
2
2
1
1
2
2
3
2
2
2
1
3
1
3
3
1
2
2
1
2
1
1
3
3
1
1
2
1
3
1
1
1
2
2
2
1
3
1
2
2
2
3
1
2
2
1
3
3
2
3
2
2
1
2
1
1
2
3
2
2
3
3
3
2
1
1
2
1
1
1
3
3
3
1
2
1
1
1
1
2
1
3
1
1
1
2
2
3
1
1
1
1
3
1
2
1
1
3
2
2
1
1
2
3
1
3
1
1
1
2
3
1
1
3
2
1
1
3
3
2
3
1
3
3
1
1
1
2
1
2
1
1
3
3
1
3
2
2
1
3
1
1
3
1
1
1
2
2
1
2
3
3
3
2
3
1
3
3
3
1
1
1
2
1
3
3
3
1
1
1
1
2
2
1
2
2
2
1
3
2
3
3
2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值