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.
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} |
9 2 2 1 3 3 3 2 3 1
A single line containing the number of exchanges required
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
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