第一题:涂面包
描述:
你要在面包片上涂layer_count层,做成山莓酱面包。考虑到每次涂酱,你只能最多涂upper_limit层,要求算出最少的涂酱次数。
分析:
要求最少的涂酱次数,只要每次涂尽可能多的山莓酱就好了。这是很典型的贪心思路。
代码:
int ToastXRaspberry::apply( int upper_limit, int layer_count) {
if (layer_count % upper_limit == 0){
return layer_count / upper_limit;
}
return layer_count / upper_limit + 1
}
第二题:烤面包
描述:
对于每一种类的面包,都有一个烧烤时间X。如果面包恰好被烤了X分钟,则称为好面包。少于X,则是不熟的;多于X就烤焦了。面包师现在烤了一些面包。由于他并不知道每种面包的确切烧烤时间,所以每个面包要不是不熟就是烤焦了。他唯一记得的是,每种面包都被烤不熟或烤焦了。现在你已知不熟面包和烤焦面包被烤的确切时间,给出至少有几种面包类被使用了。
分析:
题目比较难理解。简单的解释就是说,如果有一种面包,面包师把它烤不熟了,则面包师也把它烤焦了。因此,如果x1为最小烤焦时间,必大于最小的不熟时间y1,否则只有一种面包被烤焦了,它却没有被烤不熟,矛盾。同样的,如果x2为最大的烤焦时间,比大于最大的烤不熟时间y2,否则对那个烤不熟的面包来说,跟它同种的面包里没有被烤焦,矛盾。如果上面两种情况都不符合,则至少有一种面包被用来烤了。如果x1大于y2,则面包只有一种。否则,烧烤时间t1小于x1同时大于y1的面包,在比x1大的烤焦时间里面同样被烤焦。但由于t1小于y2,则至少还有另一种面包被烤了。由于x2大于y2,t2只要小于x2同时大于y2就可以了。这样,比y2小的所有时间,该种面包都不能烤熟。这样,可能被烤的面包种类其实最多只有两种。
代码:
int ToastXToast::bake( vector < int > undertoasted, vector < int > overtoasted) {
sort(undertoasted.begin(), undertoasted.end());
sort(overtoasted.begin(), overtoasted.end());
if (undertoasted[undertoasted.size() - 1] <= overtoasted[0]){
return 1;
}
else if (undertoasted[0] >= overtoasted[0]
|| undertoasted[undertoasted.size() - 1] >= overtoasted[overtoasted.size() - 1]){
return -1;
}
else {
return 2;
}
}
第三题:村村通公路
描述:
在一个星球上,有很多个城市和农村。农村都很孤立,没有跟城市连接起来。你现在要修建公路把农村跟城市连接起来。如果一个村已经跟城市连接起来,则其他村可以间接通过这个村和城市连接。给定所有城市和村庄的坐标,要求计算所需修建的路的最小长度。两个点之间的距离是欧氏距离。
分析:
如果用A表示城市,B表示已经跟城市连接的村庄,C表示还没跟城市连接的村庄。对C中的每个村落来说其当前要修建的公路的最少长度要么是到A中的某个城市,要么是到B中的某个村落。这时应该先建一条路把A或B跟C中距离最近的点x联通起来。如果先建到C中别的点y,则后面x还要通过C中的点z连入公路网,这个距离要比直接把x和公路网连起来要远得多。这是一个很明显的贪心性质。这意味着,我们每一次只要从C中选一个距离公路网最近的点x,添加到B中就可以了。当C中所有的点都被加入公路网,则计算就结束了,所获得的公路网就是最短的。
代码:
double KingdomXCitiesandVillagesAnother::determineLength( vector < int > cityX,
vector < int > cityY,
vector < int > villageX,
vector < int > villageY) {
int cities = cityX.size();
int villages = villageX.size();
vector < double > distance(villages);
vector < bool > flag(villages, false );
int count = 0;
double sum = 0;
for ( int i = 0;i < cities;i++){
for ( int j = 0; j < villages; ++j) {
double d = DIS(( double )cityX[i], ( double )cityY[i], ( double )villageX[j], ( double )villageY[j]);
if (i){
if (distance[j] > d){
distance[j] = d;
}
}
else {
distance[j] = d;
}
}
}
do {
int k = -1;
double min = -1;
for ( int i = 0;i < villages;i++){
if (!flag[i]){
if (k <= -1){
k = i;
min = distance[i];
}
else {
if (distance[i] < min){
k = i;
min = distance[i];
}
}
}
}
flag[k] = true ;
count++;
sum += min;
for ( int i = 0;i < villages;i++){
if (!flag[i]){
double d = DIS(( double )villageX[i], ( double )villageY[i], ( double )villageX[k], ( double )villageY[k]);
if (d < distance[i]){
distance[i] = d;
}
}
}
} while (count < villages);
return sum;
}
小结
这次的题目以第一和第三题最容易,第二道题只要理解题目,找到几个关键点就可以了。很悲剧的是,比赛的时候卡在第二道题了,自己把英文的题目看了很多遍,看明白的时候还剩下二十分钟了。二十分钟里面,自己又没发现最大烤焦时间一定要大于最大烤不熟时间,结果只写出了返回-1和1的代码,差了一个return 2。
想来每次topcoder比赛,光是看题目就已经花了半个小时,75分钟就只剩下45分了。在45分钟里需要发现题目里面蕴含的条件,在这个基础上设计有效的算法,对我来说还是挺难的。咳,还是要提高英文阅读能力,平时多练练啊。