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;
}