提问人:Jore 提问时间:11/12/2023 最后编辑:Jore 更新时间:11/13/2023 访问量:153
如何确定我的城市轰炸算法的破坏效率?[关闭]
How to determine the destructive efficiency of my city-bombing algorithm? [closed]
问:
这是我想在 C 中解决的问题:
问题
A国和B国之间爆发了一场战争,A国想通过空中轰炸摧毁首都B。但由于战争的突然爆发,双方的弹药储备都很低。由于弹药数量较少,战斗机飞行员杰夫被要求携带摧毁整个城市所需的确切数量的炸弹。每枚炸弹只能投掷到建筑物上。
B国的首都是一个有一维城市,有n座建筑物,其中每座建筑物(i)位于x轴上的某个x(i)处。杰夫必须摧毁城市中的每座建筑物。每枚炸弹都有一个破坏范围 k,这意味着它可以摧毁距离其撞击点 ≤ k 个单位的所有东西。
现在给定了城市地图和炸弹的射程k,杰夫希望你找到他摧毁整个城市所需的最小炸弹数量(每座建筑物必须在至少一枚炸弹的破坏范围内)。
输入
第一行包含两个空格分隔的整数 n(城市中的建筑物数量)和 k(每枚炸弹的破坏范围)。 第二行包含 n 个以空格分隔的整数,表示建筑物在 x 轴上的位置。
输出
打印一个整数,表示摧毁城市所需的最小炸弹数量。
约束
1 ≤ n,k ≤ 10^5
1 ≤ x ≤ 10^5
示例输入
4 2
1 2 3 4
示例输出
1
问题也可以在以下位置找到:code.dcoder.tech >挑战>硬>耗尽弹药
我的解决方案
#include <stdio.h>
#include <stdlib.h>
/* Variables named according to the problem
* n - number of buildings
* k - range of bombs
* buildings - Array containing the integer
* coordinates of the buildings
*/
int n, k, *buildings;
void getInput(void);
int isBuilding(int);
int nextBuilding(int);
int lastBuilding(int);
int main(void) {
getInput();
int bombs = 0;
/* Loops through the x cordinates from building 1 to n
* i - indicates the x coordinate where jeff is
* j - indicates the bombed area
* r - indicates the bomb range
*/
for (int i = buildings[0], j = (buildings[0] - 1), r = k; i <= buildings[n - 1] || j < buildings[n - 1]; i++, r--) {
/* When joel leaves bomb range coordinates behind */
if (r == 0) {
/* Bomb is only dropped on a building */
while (!isBuilding(i))
i--;
/* Increment bombed area (back, position and front)*/
j = i + k;
bombs++;
r = k + 1; // +1 because the loop makes r--
/* next building beyond range
* +1 because we need to leave all bombed area behind
*/
i = nextBuilding(i + k + 1);
/* if no building */
if (i == 0)
break;
else
i--; // the loop will make i++
}
}
printf("%d\n", bombs);
return 0;
}
/* Ascending comparison for qsort */
int compare(const void *a, const void *b) {
const int *aa = a;
const int *bb = b;
return (*aa > *bb) - (*aa < *bb);
}
/* Gets input for n, k and buildings,
* and sorts buildings
*/
void getInput(void) {
if (scanf("%d %d", &n, &k) != 2) {
fprintf(stderr, "input error\n");
return;
}
buildings = calloc(sizeof *buildings, n);
if (!buildings) {
fprintf(stderr, "allocation error\n");
return;
}
for (int i = 0; i < n; i++) {
if (scanf("%d", &buildings[i]) != 1) {
fprintf(stderr, "input error\n");
return;
}
}
qsort(buildings, n, sizeof *buildings, compare);
}
/* Returns 1 if it is a building,
* 0 otherwise
*/
int isBuilding(int p) {
for (int i = 0; i < n; i++) {
if (buildings[i] == p)
return 1;
}
return 0;
}
/* Returns position of next building greater or equal to p,
* 0 if none available
*/
int nextBuilding(int p) {
for (int i = 0; i < n; i++) {
if (buildings[i] >= p)
return buildings[i];
}
return 0;
}
/* Returns position of last building less or equal to p
* 0 if none available
*/
int lastBuilding(int p) {
for (int i = 0; i < n; i++) {
if (buildings[i] == p)
return buildings[i];
else if (buildings[i] > p)
return buildings[--i];
}
return 0;
}
解释
我采取更直接的方法解决这个问题,因为试图找到一个公式似乎是不可能的。
我主要使用杰夫的位置,他向前移动(炸弹射程)距离,然后在那里放置炸弹,如果当时有建筑物,或者回到最后一栋建筑物。(这个问题明确提到炸弹只能放置在建筑物上)。i
k
然后我移动到下一个未被轰炸的建筑物并重复上述过程。i
条件是当有剩余的建筑物但无法满足(已超过最后一栋建筑物)时。j < n
i <= buildings[n - 1]
i
问题
代码在我这边似乎运行良好。
除了问题中的输入之外,我还测试了各种输入(如下所示),并得到了所需的输出。
Input:
6 2
1 2 3 4 5 6
Output: 2
Input:
10 2
2 3 8 16 17 18 19 20 21 22
Output: 4
尽管当我提交问题时,所有测试都失败了。
我哪里出错了?
答:
以下是一些问题:
在函数中,将指向局部数组的指针存储到全局变量 : 中。
getInput()
temp
buildings
buildings = temp;
从 after returns 指向的数组中读取具有未定义的行为。您应该改用 或 来分配内存。
building
getInput()
malloc
calloc
此外,您还假设建筑物偏移是按升序输入的,但分配中没有表示此类约束。您可能希望在输入期间或之后对数组进行排序。
isBuilding(0)
在所有情况下都返回,因此无法测试是否存在偏移处的建筑物。如果验证了约束,这应该不是问题,但为了保持一致性,如果发现建筑物具有偏移量,则应返回。0
0
x >= 1
isBuilding(p)
1
p
这是修改后的版本:
#include <stdio.h>
#include <stdlib.h>
int compare_ints(const void *a, const void *b) {
const int *aa = a;
const int *bb = b;
return (*aa > *bb) - (*aa < *bb);
}
/* Gets input for n, k and buildings */
void getInput(void) {
if (scanf("%d %d", &n, &k) != 2) {
fprintf(stderr, "input error\n");
return;
}
buildings = calloc(sizeof *buildings, n);
if (!buildings) {
fprintf(stderr, "allocation error\n");
return;
}
for (int i = 0; i < n; i++) {
if (scanf("%d", &buildings[i]) != 1) {
fprintf(stderr, "input error\n");
return;
}
}
qsort(buildings, n, sizeof *buildings, compare_ints);
}
/* Returns 1 if it is a building, 0 otherwise */
int isBuilding(int p) {
for (int i = 0; i < n; i++) {
if (buildings[i] == p)
return 1;
}
return 0;
}
评论
编辑:
我错过了一个重要的条件,即炸弹只能投在建筑物上。它使这个答案的简单化方法无效。
编辑2
:在第二点上,条件的问题似乎没有太大不同。下面是一个更新和注释的主循环:
qsort(buildings, n, sizeof(*buildings), compare_int);
int n_bombs = 0;
for (int i = 0; i < n;)
{
// What is the first building that if we drop on it
// we won't destroy this building?
int drop = i;
while (drop < n && buildings[drop] - buildings[i] <= k)
++drop;
// Back up by one building and drop a bomb on it
--drop;
++n_bombs;
// What is the first building that was not destroyed?
int j = drop;
while (j < n && buildings[j] - buildings[drop] <= k)
++j;
// It will be our next building to consider
i = j;
}
它根据要求计算 2、3、4、7、10、11、12、13、14、15 的 4 枚炸弹。没有进一步测试。
此循环具有一些重复代码,因此函数是有序的。如果我们介绍:nextBuilding
int nextBuilding (int* buildings, int current, int radius, int total)
{
int next = current;
while (next < total && buildings[next] - buildings[current] <= radius)
++next;
--next;
return next;
}
循环压缩为
for (int i = 0; i < n;)
{
int drop = nextBuilding(buildings, i, k, n);
++n_bombs;
i = nextBuilding(buildings, drop, k, n) + 1;
}
原始无效答案如下
你在主循环中的逻辑很难遵循。这就是它的样子,假设有排序的输入(警告,未经测试的代码)。
qsort(buildings, n, sizeof(*buildings), compare_int);
int n_bombs = 0;
for (int i = 0; i < n;)
{
++n_bombs;
int last_destroyed_x = buildings[i] + 2*k; // edit: was 2*k + 1
while (i < n && buildings[i] <= last_destroyed_x)
++i;
}
不需要像 或 这样的辅助函数。isBuilding
nextBuilding
评论
i
评论
buildings
指向 中的局部数组。当函数返回时,该数组超出范围。temp
getInput