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

 

   题意:

   给出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 区间内的 22 区间内的 11 区间内的 33 区间内的 12 区间内的 3 3 区间内的 2 进行一步考虑。

  最后剩下的为 1 区间内的 2 2 区间内的 33 区间内的 11 区间内的 3 2 区间内的 13 区间内的 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;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值