【发布时间】:2021-03-21 07:18:29
【问题描述】:
谁能告诉我我的代码有什么问题?我已经通过了示例测试,但我无法通过两个实际的测试用例..
我的算法是dfs:
-
从一个矩阵的第一个元素到最后,检查一个元素与相邻的上、下、左、右的差值是否小于等于1
-
如果是,则通过 如果不是,则将最小数量的块添加到检查元素或相邻元素中以产生差异 1 并将计数增加您添加的最小块数
-
如何将最小数量添加到哪个元素: 只需选择产生绝对差异所需的最小元素 1
-
例如,您将 aij 与较低的 ai+1j 进行了比较: 如果您添加到检查元素是因为它更小,则再次从 aij+1、aij-1、ai-1j 开始递归。因为现在 aij 和 ai+1j 之间的差异符合您需要检查的标准是否与其他相邻的 否则从 ai+1j 开始递归
-
对下、上、左、右执行上述步骤
6.返回计数
问题出在: https://codingcompetitions.withgoogle.com/kickstart/round/0000000000436140/000000000068cb14
问题 芭芭拉去年在学校取得了很好的成绩,所以她的父母决定送她一只宠物兔子。她非常兴奋,为兔子建造了一个房子,可以看作是一个 R 行 C 列的 2D 网格。
兔子喜欢跳跃,所以芭芭拉在网格的几个单元格上堆放了几个盒子。每个盒子都是一个具有相同尺寸的立方体,它们与网格中一个单元格的尺寸完全匹配。
但是,芭芭拉很快意识到,兔子跳的高度超过 1 格可能很危险,因此她决定通过对房子进行一些调整来避免这种情况。对于每一对相邻的单元格,芭芭拉希望它们的绝对高度差最多为 1 个盒子。如果两个单元格共享一个公共边,则认为它们是相邻的。
由于所有盒子都是强力胶粘的,Barbara 无法移除最初存在的任何盒子,但她可以在它们上面添加盒子。她可以添加任意数量的框,添加任意数量的单元格(可能为零)。帮助他确定要添加的最少盒子总数是多少,这样兔子的房子就安全了。
输入 输入的第一行给出了测试用例的数量,T.T 测试用例紧随其后。
每个测试用例都以包含两个整数 R 和 C 的行开头。
然后,接下来是 R 行,每行都有 C 个整数。第 i 行的第 j 个整数 Gi,j 表示位于网格第 i 行第 j 列的单元格上最初有多少个框。
输出 对于每个测试用例,输出一行包含 Case #x: y,其中 x 是测试用例编号(从 1 开始),y 是要添加的最小盒子数,以便兔子的房子是安全的。
限制 内存限制:1 GB。 1≤T≤100。 0≤Gi,j≤2⋅106,对于所有 i, j。 测试集 1 时间限制:20秒。 1≤R,C≤50。 测试集 2 时间限制:40秒。 1≤R,C≤300。
这是我的 C++ 代码:
#include <iostream>
#include <string>
#include <cstdlib>
#include <vector>
using namespace std;
void solve(vector<vector<int>> &v,
int ii, int jj,
int r, int c, int& cnt) {
if (ii<0 || ii>r - 1 || jj<0 || jj>c - 1) return;
int ads;
if (ii + 1 < r) {
if (abs(v[ii][jj] - v[ii + 1][jj]) > 1) {
ads = min(abs(v[ii + 1][jj] - v[ii][jj] - 1),
abs(v[ii + 1][jj] - v[ii][jj] + 1));
cnt += ads;
if (v[ii + 1][jj] < v[ii][jj]) {
v[ii + 1][jj] += ads;
solve(v, ii + 1, jj, r, c, cnt);
}
else {
v[ii][jj] += ads;
solve(v, ii, jj - 1, r, c, cnt);
solve(v, ii, jj + 1, r, c, cnt);
solve(v, ii - 1, jj, r, c, cnt);
}
}
}
if (ii - 1 > -1) {
if (abs(v[ii][jj] - v[ii - 1][jj]) > 1) {
ads = min(abs(v[ii - 1][jj] - v[ii][jj] - 1),
abs(v[ii - 1][jj] - v[ii][jj] + 1));
cnt += ads;
if (v[ii - 1][jj] < v[ii][jj]) {
v[ii - 1][jj] += ads;
solve(v, ii - 1, jj, r, c, cnt);
}
else {
v[ii][jj] += ads;
solve(v, ii, jj - 1, r, c, cnt);
solve(v, ii, jj + 1, r, c, cnt);
solve(v, ii + 1, jj, r, c, cnt);
}
}
}
if (jj - 1 > -1) {
if (abs(v[ii][jj] - v[ii][jj - 1]) > 1) {
ads = min(abs(v[ii][jj - 1] - v[ii][jj] - 1),
abs(v[ii][jj - 1] - v[ii][jj] + 1));
cnt += ads;
if (v[ii][jj - 1] < v[ii][jj]) {
v[ii][jj - 1] += ads;
solve(v, ii, jj - 1, r, c, cnt);
}
else {
v[ii][jj] += ads;
solve(v, ii, jj + 1, r, c, cnt);
solve(v, ii - 1, jj, r, c, cnt);
solve(v, ii + 1, jj, r, c, cnt);
}
}
}
if (jj + 1 < c) {
if (abs(v[ii][jj] - v[ii][jj + 1]) > 1) {
ads = min(abs(v[ii][jj + 1] - v[ii][jj] - 1),
abs(v[ii][jj + 1] - v[ii][jj] + 1));
cnt += ads;
if (v[ii][jj + 1] < v[ii][jj]) {
v[ii][jj + 1] += ads;
solve(v, ii, jj + 1, r, c, cnt);
}
else {
v[ii][jj] += ads;
solve(v, ii, jj - 1, r, c, cnt);
solve(v, ii - 1, jj, r, c, cnt);
solve(v, ii + 1, jj, r, c, cnt);
}
}
}
return;
}
int main() {
// your code goes here
int t;
cin>>t;
int r, c, m;
for (int i = 0; i < t; i++) {
cin >> r >> c;
vector<vector<int>> v(r,vector<int>(c,0));
for (int j=0;j<r;j++){
for (int k=0;k<c;k++){
cin>>m;
v[j][k]=m;
}
}
int cnt=0;
for (int j=0;j<r;j++){
for (int k=0;k<c;k++){
solve(v,j,k,r,c,cnt);
}
}
cout << "Case #" << i + 1 << ": " << cnt<<endl;
}
return 0;
}
我已经通过了示例案例: 样本 样本输入 3 1 3 3 4 3 1 3 3 0 0 3 3 0 0 0 0 2 0 0 0 0 样本输出 案例#1:0 案例#2:3 案例#3:4
但不是实际的测试用例...非常感谢任何帮助!
【问题讨论】:
-
提示:你不需要
abs函数,你需要一个优先队列。顺便说一句,如果你描述你的算法,你可能会有更多的运气,而不是期望人们对代码进行逆向工程来发现你的算法。 -
谢谢,我不明白为什么我需要优先级队列,但我按照你的建议描述了我的算法。谢谢!
-
啊,我现在明白你要做什么了。似乎该算法可以工作,并且代码似乎通常遵循该算法。我没有在代码中看到任何特别错误的地方,但是有很多机会出现一对一错误和 x-y 交换。要调试这样的代码,您需要测试代码中所有可能路径的示例输入。
-
我将描述我暗示的方法,以防您感兴趣。找到矩阵中最高的堆栈(称为高度 H)。调整四个相邻的堆栈,使它们至少有 H-1 个盒子高。冲洗并重复。这种方法的问题在于它是 O(N^2),其中 N=R*C。解决方案是使用优先级队列,以便在每个步骤中轻松找到最高的堆栈。使用优先级队列,运行时间减少到 O(NlogN)。
-
我已经测试了许多样本并调试了代码,但看不出它为什么会失败。我在这个问题上花了很多时间,所以我希望有人能看到我错过的错误????但是感谢您的评论 nlogn 比我的快!
标签: algorithm