HrbustOJ1176

HrbustOJ1176 小陈老师、雪人

东北的冬季,尤其是过年的时候,小陈老师喜欢去堆雪人。

每个雪人主要由三个雪球构成:大雪球、中雪球、小雪球。

他已经准备好了N个雪球,半径分别等于r1, r2, ..., rn。如果要堆一个雪人,就需要三个半径互不相等的雪球。

例如:

三个雪球的半径为1、2、3,能够用来堆一个雪人。但是半径为2、2、3或者2、2、2的三个雪球就不可以。

快帮帮小陈老师,算算他最多能用这些雪球堆多少个雪人。

输入:对于每组测试数据:

第1行,包含一个整数n(1≤n≤100000) —雪球的数量。

第2行,包含n个整数 — 雪球的半径r1, r2, ..., rn (1≤ri≤1000000000)。

处理到文件结束

输出:对于每组测试数据:

第1行,输出最多能堆多少雪人 - k。

接下来k行,每行描述一个雪人,每行用空格分割三个数字分别表示大雪球、中雪球、小雪球的半径。

可以用任何顺序输出每个雪人。如果有多种可行解,输出任意一个即可。

分析:如果n个雪球的半径都不一样,能构成n/3个雪人。现在有这种情况:

雪球半径:1 2 3 4

雪球个数:1 2 2 1

如果先选1 3 4 作为雪人,那么剩下两个2号 1个3号不能作为一个雪人。所以应该先选 2 3 1 作为雪人,然后选2 3 4做雪人。

贪心策略:始终选择当前个数最多的前三个不同雪球构成一个雪人。但是这个策略如何证明其正确性呢?

AC代码:

#include<cstdio>
#include<queue>
#include<map>
#include<algorithm>
using namespace std;

struct node//保存对应value大小的雪球共有多少个num
{
    int value;//值·
    int num;//数量
    friend bool operator<(node a,node b)
    {
        return a.num < b.num;
    }
};
priority_queue<node>q;//用于提取前3多的雪球
map<int ,int> m;//m[2]=5表示大小为2的雪球共有5个
int min_v[100000+1000],mid_v[100000+1000],max_v[100000+1000];//用于记录最后的输出数据
void get_v(int x,int y,int z,int &min_v,int &mid_v,int &max_v)//得到X,Y,Z中的最大值与最小值
{
    max_v = max(x,y);
    max_v = max(max_v,z);
    min_v = min(x,y);
    min_v = min(min_v,z);
    mid_v = x+y+z-min_v-max_v;
}
int main()
{
    int n;
    while(scanf("%d",&n)==1&&n)
    {
        while(!q.empty()) q.pop();//初始化清空优先队列和map
        m.clear();
        while(n--)
        {
            int v;//雪球半径
            scanf("%d",&v);
            m[v]++;
        }
        node node_i,node_1,node_2,node_3;
        for(map<int, int>::const_iterator iter = m.begin(); iter != m.end(); ++iter)//将map数据导入优先队列
        {
            node_i.value = iter->first;
            node_i.num = iter->second;
            q.push(node_i);
        }
        int sum = 0;//记录最终有多少个 雪人
        while(!q.empty())//取雪球
        {
            node_1 = q.top();
            q.pop();
            if(!q.empty())//取第二个雪球
            {
                node_2 = q.top();
                q.pop();
            }
            else
            {
                break;
            }
            if(!q.empty())//取第三个雪球
            {
                node_3 = q.top();
                q.pop();
            }
            else
            {
                break;
            }

            get_v(node_1.value,node_2.value,node_3.value,min_v[sum],mid_v[sum],max_v[sum]);//得到最大中小值
            //printf("%d %d %d\n",max_v[sum],mid_v[sum],min_v[sum]);
            
            if(--node_1.num)//雪球如果有剩余还得继续入队列
                q.push(node_1);

            if(--node_2.num)
                q.push(node_2);

            if(--node_3.num)
                q.push(node_3);

            sum++;
        }
        printf("%d\n",sum);//打印结果
        for(int i=0;i<sum;i++)
            printf("%d %d %d\n",max_v[i],mid_v[i],min_v[i]);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值