这题一开始我想成了逆序,然后写了之后才发现不对。于是就在想,后来我想到了下面的方法
首先求得1的个数k1和2的个数k2。然后我们对前k1个数进行操作,如果是排序好了的话,这前k1个数应该是1,如果是2的话,那么我们从第k2+1个数开始找1,找到第一个1后交换两个数(这样交换的次数是最少的)。如果是3的话,就从最后一个数往前找第一个1,然后交换两个数。同样这样交换的次数是最少的。对1操作完了之后,我们在对接下来的k2个数进行操作,如果不是2的话,就一定是3了,一定要交换。这样进行操作之后对后面的数就不用操作了,因为已经是排好序了的。
不过官方的我还没看贴下官方的报告吧
官方报告
  1We 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. 
  2
  3A 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. 
  4
  5The 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. 
  6
  7#include <stdio.h>
  8#include <stdlib.h>
  9#include <string.h>
 10#include <assert.h>
 11
 12#define MAXN     1000
 13
 14int n;
 15int have[MAXN];
 16int want[MAXN];
 17
 18int
 19intcmp(const void *a, const void *b)
 20{
 21    return *(int*)a - *(int*)b;
 22}

 23
 24void
 25main(void)
 26{
 27    int i, j, k, n, nn[4], nswap, nbad;
 28    FILE *fin, *fout;
 29
 30    fin = fopen("sort3.in""r");
 31    fout = fopen("sort3.out""w");
 32    assert(fin != NULL && fout != NULL);
 33
 34    fscanf(fin, "%d"&n);
 35
 36    for(i=0; i<n; i++{
 37    fscanf(fin, "%d"&have[i]);
 38    want[i] = have[i];
 39    }

 40    qsort(want, n, sizeof(want[0]), intcmp);
 41
 42    /**//* swaps that correct two elements */
 43    nswap = 0;
 44    for(i=0; i<n; i++)
 45    for(j=0; j<n; j++{
 46    if(have[i] != want[i] && have[j] != want[j]
 47            && have[i] == want[j] && have[j] == want[i]) {
 48        have[i] = want[i];
 49        have[j] = want[j];
 50        nswap++;
 51    }

 52    }

 53
 54    /**//* remainder are pairs of swaps that correct three elements */
 55    nbad = 0;
 56    for(i=0; i<n; i++)
 57    if(have[i] != want[i])
 58        nbad++;
 59
 60    assert(nbad%3 == 0);
 61    nswap += nbad/3 * 2;
 62
 63    fprintf(fout, "%d\n", nswap);
 64    exit(0);
 65}

 66
 67Dan Jasper from Germany writes: 
 68
 69The 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. 
 70
 71#include <stdio.h>
 72
 73int list[1000], N, res, count[3], start[3];
 74in[3][3]; // this counts the number of "1"s in bucket "2", 
 75
 76void readFile() {
 77    FILE *f; int i;
 78    f = fopen("sort3.in""r");
 79    fscanf(f, "%d"&N);
 80    for(i = 0; i < N; i++{
 81        fscanf(f, "%d"&list[i]);
 82    }

 83    fclose(f);
 84}

 85
 86void writeFile() {
 87    FILE *f;
 88    f = fopen("sort3.out""w");
 89    fprintf(f, "%d\n", res);
 90    fclose(f);
 91}

 92
 93void findBuckets() {
 94    int i;
 95    for(i = 0; i < N; i++) count[list[i]-1]++;
 96    start[0= 0;
 97    start[1= count[0];
 98    start[2= count[0+ count[1];
 99}

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

106   }

107
108void sort() {
109    int h;
110    // 1 <-> 2
111    h = in[0][1];
112    if(in[1][0< h) h = in[1][0];
113    res += h; in[0][1-= h; in[1][0-= h;
114    // 3 <-> 2
115    h = in[2][1];
116    if(in[1][2< h) h = in[1][2];
117    res += h; in[2][1-= h; in[1][2-= h;
118    // 1 <-> 3
119    h = in[0][2];
120    if(in[2][0< h) h = in[2][0];
121    res += h; in[0][2-= h; in[2][0-= h;
122
123    // Cycles
124    res += (in[0][1+ in[0][2]) * 2;
125}

126
127void process() {
128    findBuckets();
129    findWhere();
130    sort();
131}

132
133int main () {
134    readFile();
135    process();
136    writeFile();
137    return 0;
138}

139
140Bulgaria's Evgeni Dzhelyov writes: 
141
142I 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). 
143
144Here is the source code: 
145
146#include <fstream>
147
148using namespace std;
149
150int min (int a, int b) return a < b ? a : b; }
151int max (int a, int b) return a > b ? a : b; }
152
153int main () {
154    int s[1024];
155    int n;
156    int sc[4= {0};
157    
158    ifstream fin("sort3.in");
159    ofstream fout("sort3.out");
160    fin>>n;
161    for (int i = 0; i < n; i++{
162        fin>>s[i];
163        sc[s[i]]++;
164    }

165    int s12 = 0, s13 = 0, s21 = 0, s31 = 0, s23 = 0, s32 = 0;
166    for (int i = 0; i < sc[1]; i++){
167        if (s[i] == 2) s12++;
168        if (s[i] == 3) s13++;
169    }

170    
171    for (int i = sc[1]; i < sc[1]+sc[2]; i++){
172        if (s[i] == 1) s21++;
173        if (s[i] == 3) s23++;
174    }

175    
176    for (int i = sc[1]+sc[2]; i < sc[1]+sc[2]+sc[3]; i++){
177        if (s[i] == 1) s31++;
178        if (s[i] == 2) s32++;
179    }

180    
181    fout<<min(s12, s21)+min(s13, s31)+min(s23, s32) +
182                    2*(max(s12, s21) - min(s12, s21))<<endl;
183    return 0;
184}

185
186