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