CSDN 编程竞赛三十期:比赛详情 (csdn.net)
天然气运输成本昂贵,危险性高,为了节省运输成本,提倡绿色环保,需要尽可能的优化订单配送,比如相同地区的天然气订单可以一次性配送。现需要向多个地区运输天然气。但是同一个地区可能有多个订单需求。当前仅只知道某些成对的订单是同一个地区的,同一个地区的天然气需要尽可能一次性配送从而降低运输成本,所以需要尽可能地将同一个地区的订单放在一起。订单的编号是1到n。
#include
#include
int data [100005];
struct node {
int nId;
int cId;
};
int search (int x) {
return data [x] == x ? x : data [x] = search (data [x]);
}
void input (node* p) {
scanf ("%d", &p -> nId);
p -> cId = search (p -> nId);
}
int main () {
int n, m;
scanf ("%d %d", &n, &m);
for (int i = 1; i <= n; i++) data [i] = i;
for (int i = 1; i <= m; i++) {
node x, y;
input (&x);
input (&y);
data [(x.cId < y.cId ? y : x).cId] = (x.cId < y.cId ? x : y).cId;
}
std::vector result [n + 1];
for (int i = 1; i <= n; i++) {
result [data [i] == i ? i : search (data [i])].push_back (i);
}
for (int i = 1; i <= n; i++) {
if (i > 1 && result [i - 1].size () > 0) printf ("\n");
for (unsigned int j = 0; j < result [i].size (); j++) {
if (j > 0) printf (" ");
printf ("%d", result [i][j]);
}
}
return 0;
}
使用并查集算法,将有关联的订单归到一类。
相较传统并查集算法的题目而言,这道题多了一步统计的过程。需要将属于同一类别的订单放到对应列表中,最后集中输出即可。
因此,在归类过程中,如果同一类中有更小的订单号,可以用较小值表示该类型。例如,1 4 5是一类,2 3是一类,则分别可以用1和2代表这两类的订单。这样做可以为最后的统计操作提供便利。
书是人类进步的阶梯。小艺每周因为工作的原因会选择性的每天多读几页或者少读几页。小艺想知道一本n页的书她会在周几读完。
#include
int main () {
int n; scanf ("%d", &n);
int data [7]; for (int i = 0; i < 7; i++) scanf ("%d", &data [i]);
int d; for (d = 0; n > 0; d = (d + 1) % 7) n = n - data [d];
return 0;
}
直接暴力模拟,从周一开始,每次减少当天对应的页数,如果还有剩余页数继续跳到下一天,否则就停下来。这里有个优化点,可以一次性减去一周能看完的页数,直到剩余的页数不足一周的量时,再逐天判断。
小易去附近的商店买苹果,奸诈的商贩使用了捆绑交易,只提供6个每袋和8个每袋的包装(包装不可拆分)。可是小易现在只想购买恰好n个苹果,小易想购买尽量少的袋数方便携带。如果不能购买恰好n个苹果,小易将不会购买。
int main () {
int result = -1;
int n;
scanf ("%d", &n);
int n_6 = n / 6 + 1;
for (int i = 0; i < n_6; i++) {
for (int j = 0; j < n_6; j++) {
if (i * 6 + j * 8 == n) {
if (i + j < result || result == -1) result = i + j;
}
}
}
return 0;
}
题目比较简单,直接一项一项去试就可以了。找到符合条件的情况时,再判断一下袋数是不是比之前的消耗量要小,如果更小就更新答案,直到找到最优解为止。
也可以使用贪心算法来求解,先判断一下要购买的苹果是否为偶数,如果不是偶数直接返回-1。
首先,假设全部买8个每袋的商品,不足的用6个每袋的商品补齐,确保买到的苹果数不少于需求量。
之后,减少8个每袋的商品数量,如果过程中买到的苹果数少于预期的话再增加6个每袋的商品。
直到找到恰好满足条件的解时,跳出循环。
这种方法理论可行,不过比赛时比较考验手速,博主并未尝试,只是提供一个思路,感兴趣的小伙伴可以自己试一下。
有N个客人与足够多张的圆桌。主人安排每位客人坐在一个圆桌边,但是每位客人希望自己左右边上分别有一些空座位,不然会觉得害羞。注意,如果一个客人所在的圆桌只有他一个人,那么他左边的空座位数量就是他右边的空座位数量。试问主人需要准备多少个座位,才能让每个客人舒适的坐下。
#include
#include
long long int data1 [1000005];
long long int data2 [1000005];
int main () {
long long int result = 0;
long long int n;
scanf ("%lld", &n);
for (long long int i = 0; i < n; i++) scanf ("%lld %lld", &data1 [i], &data2 [i]);
std::sort (data1, data1 + n);
std::sort (data2, data2 + n);
for (long long int i = 0; i < n; i++) result = result + max (data1 [i], data2 [i]);
return 0;
}
贪心算法。尽量让空位能够拟合,计算之后还要加上n才能得到最终结果。
这道题在第11期竞赛时出现过一次。需要注意数据范围,必须用long long int才能全部通过,否则只能通过90%的测试数据。