这题一开始我想成了逆序,然后写了之后才发现不对。于是就在想,后来我想到了下面的方法
首先求得1的个数k1和2的个数k2。然后我们对前k1个数进行操作,如果是排序好了的话,这前k1个数应该是1,如果是2的话,那么我们从第k2+1个数开始找1,找到第一个1后交换两个数(这样交换的次数是最少的)。如果是3的话,就从最后一个数往前找第一个1,然后交换两个数。同样这样交换的次数是最少的。对1操作完了之后,我们在对接下来的k2个数进行操作,如果不是2的话,就一定是3了,一定要交换。这样进行操作之后对后面的数就不用操作了,因为已经是排好序了的。
不过官方的我还没看贴下官方的报告吧
首先求得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
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