写在前面:
本系列博客仅作为本人十一假期过于无聊的产物,对小学期的程序设计作业进行一个总结式的回顾,如果将来有BIT的学弟学妹们在百度搜思路时翻到了这一条博客,也希望它能对你产生一点帮助(当然,依经验来看,每年的题目也会有些许的不同,所以不能保证每一题都覆盖到,还请见谅)。
不过本人由于学艺不精,代码定有许多不足之处,欢迎各位一同来探讨。
同时请未来浏览这条博客的学弟学妹们注意,对于我给出完整代码的这些题,仅作帮助大家理解思路所用(当然,因为懒,所以大部分题我都只给一个伪代码)。Anyway,请勿直接复制黏贴代码,小学期的作业也是要查重的,一旦被查到代码重复会严厉扣分,最好的方法是浏览一遍代码并且掌握相关的要领后自己手打一遍,同时也要做好总结和回顾的工作,这样才能高效地提升自己的代码水平。
加油!
成绩 | 10 | 开启时间 | 2021年08月31日 星期二 12:30 |
折扣 | 0.8 | 折扣时间 | 2021年09月7日 星期二 23:00 |
允许迟交 | 否 | 关闭时间 | 2021年10月10日 星期日 23:00 |
Description
和许多同龄女孩子一样,久莲也喜欢水晶球。
还有10
天,就是心心念念的他生日了。
久莲希望把全世界最大最好看的水晶球送给他。
她找到了宝石收藏家亚瑟斯,希望能够寻求他的帮助。
亚瑟斯很快被打动了,拿出了精心收集的n块美丽的水晶石,这些水晶石初始是长宽高分别为a,b,c的长方体。亚瑟斯许诺久莲可以从中取走1
块水晶石作为她礼物的原材料。
同时亚瑟斯有一种魔法,如果这两块长方形水晶石在某一个面能够完美的契合在一起(完美的契合是指这两个长方形面全等),那么可以将它们融合成一块完整的大石头,如果真的实现的话,那么久莲就可能打磨出更大的水晶球啦!
久莲太希望把最美最大的水晶球送给他了,你快帮帮她如何选择吧。
Input
第一行输入一个正整数。
在接下来n行中,第i行输入三个正整数表示第i块水晶的长宽高,注意可能有两个长得一模一样的水晶石,但是在这种情况下还是将它们视作是两块不同的水晶石。
Output
第一行请输出一个正整数 1或2,表示久莲选择的水晶球数量。
第二行请输出k个正整数,如果k=1,请输出一个正整数表示久莲选择的水晶石。如果k=2,则请输出两个正整数
(用空格间隔),表示久莲希望亚瑟斯帮她将编号为x,y
的水晶石融合成一块更大的水晶石,并选择用这块水晶石来打磨加工。请注意,这两块水晶石必须满足 “完美契合” 的条件,否则这个选择不合法。如果有多种最优的选择,则你可以输出任意一种合法的最优方案。
Hint
对于样例,如果久莲选择第六个水晶球,那么她可以打磨成半径为r=2.5 的水晶球,这是最优的选择。
测试用例 1 | 以文本方式显示
| 以文本方式显示
| 1秒 | 64M |
题意分析:
不用说应该也能猜到,这题还是排序+贪心的思路。(废话,周标题都写在那了)
我们先不考虑融合的情况,先来研究一下怎么样才能打磨出最大的水晶球吧。根据我们的初中数学知识,不难知道,长方体内取一个最大的球,球的半径应该等于长方体最短边的长度,所以不考虑融合的时候,我们只关注长方体最短的那个边,这是这题贪心思想的一个体现。
那么考虑融合了会怎么样呢?假设长方体有三条边,从小到大依次是,那么融合只有三种可能:
相等,
相等,
相等。然而前两种融合方法,并不会改变最短边依然是
的事实,所以真正有效的融合方法应该是第三种,融合后的最短边为
。
好了,这题基本上已经做完了,接下来仅仅需要考虑的就是如何搜索那些可以融合的水晶了。
首先,的暴力搜索,我们直觉上就觉得不行——因为这个融合的条件显然是可控的,并不是那么漫无目的地乱搜。融合的必要条件是“最长的两边”相等(因为我们只考虑上述第三种融合情况了,前两种融合情况对于寻找更优解没有意义)。换句话说,如果我们按照最长边、次长边、最短边的优先级来排序,所有能够融合的水晶都是扎堆出现的;而且,这些扎堆出现的
相等的水晶们里面,我们只需要考虑后两个——因为他们是
最大的两个,对于相同的
,我们只需要考虑他们就足够了,前面的那些无论如何表现不会比他们更好,这也是贪心思想的体现。
具体的实现应该不难了,我就放在下面的代码和伪代码里,如果还没有读明白的读者可以多琢磨琢磨,贪心的题目就是这样,你可能看了半天都没看懂,忽然某个瞬间就顿悟了。
伪代码:
读入数据,对每个数据内部进行排序,保证,再将所有的数据保存到一个容器里;
对容器按照的优先级排序;//和上一题类似,可以重载“<”操作符,直接sort排序
维护一个变量用于保存我们选定的球的相关信息;//需要保存哪些信息?请读者自行思考
遍历容器:
如果某单个水晶的最小边就已经大于保存的半径,更新
;
同时检查一下这个单个的水晶是否能与其他水晶匹配,方法就是看他的下一个水晶的是否与他相等,如果是的话,不断往后搜索直到找到这一堆
相等的水晶的最后两个,他们就是这一堆能够合成的最大的水晶;
比较合成后的水晶和,如果更大,更新
;
遍历结束后,输出 ;
贴代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f;
struct ball{ //用于保存水晶,同时要记录水晶的原始下标,防止排序后被打乱
int x = 0;
int y = 0;
int z = 0;
//ensure that x <= y <= z
int index1 = -1;
int index2 = -1;
}temp, target;
inline void bSort(ball& ball){ //对水晶内部的三个参数进行排序,保证x <= y <= z
int t;
if(ball.x > ball.y){
t = ball.y;
ball.y = ball.x;
ball.x = t;
}
if(ball.y > ball.z){
t = ball.z;
ball.z = ball.y;
ball.y = t;
}
if(ball.x > ball.y){
t = ball.y;
ball.y = ball.x;
ball.x = t;
}
}
struct cmp{ //重载“<”操作符,用来给sort函数使用
bool operator()(ball p, ball q){
if(p.z < q.z)
return true;
else if(p.z == q.z){
if(p.y < q.y)
return true;
else if(p.y == q.y){
if(p.x < q.x)
return true;
else
return false;
}
else return false;
}
else return false;
}
};
int main(){
///ifstream infile("input.txt", ios::in);
///ofstream outfile("output.txt", ios::out);
vector<ball> list;
int n;
cin >> n;
for(int i = 0; i < n; i++){
cin >> temp.x >> temp.y >> temp.z;
temp.index1 = i;
bSort(temp);
list.push_back(temp);
}
sort(list.begin(), list.end(), cmp());
/*for(int i = 0; i < n; i++){
cout << list[i].x << ' ' << list[i].y << ' ' << list[i].z << endl;
}*/
int pt = 0;
bool canCompound = false;
while(pt != n){
if(list[pt].x > target.x) { //更新target
target.x = list[pt].x;
target.index1 = list[pt].index1;
target.index2 = -1;
}
canCompound = false;
//cout << list[pt].y << ' ' << list[pt+1].y << ' ' << list[pt].z << ' ' << list[pt+1].z << endl;
while(list[pt].y == list[pt+1].y and list[pt].z == list[pt+1].z){
//寻找能够融合的一组水晶中x最大的两个
canCompound = true;
pt++;
if(pt == n - 1) break;
}
if(canCompound){ //更新target
//if(list[pt].y < target.x) break;
temp.index1 = list[pt].index1;
temp.index2 = list[pt-1].index1;
temp.x = list[pt].x + list[pt-1].x;
temp.y = list[pt].y;
temp.z = list[pt].z;
bSort(temp);
if(temp.x > target.x) target = temp;
}
pt++;
if(pt == n) break;
}
//输出
if(target.index2 == -1){
cout << 1 << endl << target.index1 + 1 << endl;
}
else{
if(target.index1 < target.index2)
cout << 2 << endl << target.index1 + 1 << ' ' << target.index2 + 1 << endl;
else
cout << 2 << endl << target.index2 + 1 << ' ' << target.index1 + 1 << endl;
}
return 0;
}