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
题意:
给出N(1~1000)个数,每个数只有3种情况 1,2 或 3。一次可以交换两个数,算出最少步数使原序列变为不下降序列。
思路:
贪心。
先统计出1,2,3 各自的总数num1,num2,num3,说明在1 ~ num1 内的数应该为1,在num1 ~ num1 + num2 内的数应该为2,只 num1 + num2 ~ num3 之间的数应该为3。同时统计在这单个区间每一种数的个数。
每一次操作可以对两个数进行交换,所以一次最多可以纠正出两个错误的数,同样说明最少可能有两个数同时错,最多可能有三个数都错。那么列举所有情况出来:
1. 需要交换一次(说明两个数是错的)纠正错误的序列可能为:2,1,3 ;3,2,1 ;1,3,2 三种情况;
2. 需要交换两次(说明三个数是错的)纠正错误的序列可能为:2,3,1 ;3,1,2 两种情况;
对于已经在正确位置上的数则不再考虑。
因为要求步数最少,所以想考虑 "交换一次" 的情况,再考虑 ”交换两次“ 的情况。如果通过 ”交换一次“ 能纠正所有的数而不用进行 ”交换两次“ 则当前步数则为最少。
所以先对 1 区间内的 2 和 2 区间内的 1,1 区间内的 3 和 3 区间内的 1 ,2 区间内的 3 和 3 区间内的 2 进行一步考虑。
最后剩下的为 1 区间内的 2 和 2 区间内的 3 和 3 区间内的 1,1 区间内的 3 和 2 区间内的 1 和 3 区间内的 2 进行两部考虑,最后全部步数相加即为所求。
AC:
/* TASK:sort3 LANG:C++ ID:sum-g1 */ #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; typedef struct { int one,two,thr,sum; }node; node no[4]; int num[1005]; int main() { freopen("sort3.in","r",stdin); freopen("sort3.out","w",stdout); int n,sum = 0,minnum,ans = 0; scanf("%d",&n); memset(no,0,sizeof(no)); for(int i = 1;i <= n;i++) { scanf("%d",&num[i]); no[num[i]].sum++; } for(int i = 1;i <= n;i++) { if(num[i] == 1) { if(i <= no[1].sum) no[1].one++; if(i > no[1].sum && i <= no[2].sum + no[1].sum) no[2].one++; if(i > no[2].sum + no[1].sum) no[3].one++; } if(num[i] == 2) { if(i <= no[1].sum) no[1].two++; if(i > no[1].sum && i <= no[2].sum + no[1].sum) no[2].two++; if(i > no[2].sum + no[1].sum) no[3].two++; } if(num[i] == 3) { if(i <= no[1].sum) no[1].thr++; if(i > no[1].sum && i <= no[2].sum + no[1].sum) no[2].thr++; if(i > no[2].sum + no[1].sum) no[3].thr++; } } ans += min(no[1].two,no[2].one); no[1].two -= min(no[1].two,no[2].one); no[2].one -= min(no[1].two,no[2].one); ans += min(no[1].thr,no[3].one); no[1].thr -= min(no[1].thr,no[3].one); no[3].one -= min(no[1].thr,no[3].one); ans += min(no[2].thr,no[3].two); no[2].thr -= min(no[2].thr,no[3].two); no[3].one -= min(no[2].thr,no[3].two); ans += (no[1].two + no[1].thr) * 2; printf("%d\n",ans); return 0; }