Программа A с глобальными переменными x
и y
:
#include <cstdio>
#include <vector>
using namespace std;
const int maxn = 3000000 + 10;
int dp[maxn], n, maxy;
int x, y; // <-- Global variables `x` and `y`
vector<int> a[maxn];
int main() {
freopen("demo.txt", "r", stdin);
freopen("demo.out", "w", stdout);
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
//int x, y;
scanf("%d %d", &x, &y);
a[y].push_back(x-1);
maxy = max(maxy, y);
}
for (int i = 1; i <= maxy; i++) {
dp[i] = dp[i - 1];
if (a[i].size() == 0) continue;
for (int j = 0; j < a[i].size(); j++) {
int u = a[i][j];
dp[i] = max(dp[i], dp[u] + i - u);
}
}
printf("%d\n", dp[maxy]);
return 0;
}
Программа B, почти такая же, как программа A, но с локальными переменными x
и y
(x
и y
можно рассматривать как две конечные точки интервала, что $x < y$).
#include <cstdio>
#include <vector>
using namespace std;
const int maxn = 3000000 + 10;
int dp[maxn], n, maxy;
//int x, y;
vector<int> a[maxn];
int main() {
freopen("demo.txt", "r", stdin);
freopen("demo2.out", "w", stdout);
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
int x, y; // <-- Local variables `x` and `y`
scanf("%d %d", &x, &y);
a[y].push_back(x-1);
maxy = max(maxy, y);
}
for (int i = 1; i <= maxy; i++) {
dp[i] = dp[i - 1];
if (a[i].size() == 0) continue;
for (int j = 0; j < a[i].size(); j++) {
int u = a[i][j];
dp[i] = max(dp[i], dp[u] + i - u);
}
}
printf("%d\n", dp[maxy]);
return 0;
}
Инструкция компиляции (с оптимизацией -O2):
g++ demo.cpp -o demo.exe -O2 -std=c++14
Скомпилируйте информацию:
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=C:/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/lto-wrapper.exe
Target: x86_64-w64-mingw32
Thread model: posix
gcc version 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project)
Эти две программы получают разные результаты при одних и тех же входных данных!
Используя одни и те же входные данные, я просмотрел переменные x
, y
, maxy
, a[i]
, и все они получили одинаковые данные. А элемент массива dp[i]
получил другие данные. Я не знаю почему, переменные dp[i]
и x
, y
не связаны!
И если я скомпилирую их без инструкции -O2
, то есть g++ demo.cpp -o demo.exe -std=c++14
, они получат тот же результат!
Большие входные данные можно найти здесь: https://ww0.lanzouq.com/iesib26alt6f
Это файл txt
, содержащий около 150 001 строки.
КСТАТИ: Эта программа является решением этого вопроса , однако вы можете игнорировать эту информацию. Проблема, с которой я столкнулся, похоже, не имеет никакого отношения к этому вопросу.
Вы уверены, что scanf
действительно получится? Поскольку вы просто игнорируете его возвращаемое значение...
@AdrianJałoszewski, какой код UB? Это int j = 0
? Я перешел на vector<int>::size_type j = 0
и столкнулся с той же проблемой.
К сожалению, некоторые ссылки в вашем вопросе ведут на некоторые китайские сайты. А некоторые из них даже хотят, чтобы мы вошли в систему, чтобы получить доступ к тому, чем вы хотите поделиться.
В качестве примечания: рассмотрите возможность использования более читаемых имен переменных, чем просто a
, n
, u
, dp
и т. д. — наличие нескольких строк типа dp[i] = max(dp[i], dp[u] + i - u);
затрудняет анализ кода (по крайней мере, для меня).
Насколько велик ваш стек? Некоторые из ваших массивов довольно велики. Имеет ли значение статическое значение dp[]?
Если первый scanf("%d %d", &x, &y);
не сработал, ваша программа имеет неопределенное поведение, поскольку вы используете неинициализированные переменные. Если y
когда-либо меньше 0 или больше 3000009, то ваша программа имеет неопределенное поведение, поскольку вы получаете доступ к a
за пределами границ. Если x
когда-либо меньше 1 или больше 3000010, то ваша программа имеет неопределенное поведение, поскольку вы получаете доступ к dp
за пределами границ.
d[0]
никогда не инициализировался на первой итерации второго цикла, поэтому считываемое значение может быть любым.
@user1139069 глобальные переменные всегда инициализируются значением (по стандарту), они всегда будут содержать 0, это поведение определяется стандартом.
Ссылка на задание требует регистрации. Лучше скопировать описание задачи в вопрос.
ваш входной файл в строке 3076 содержит
0 437122
тогда в вашем коде вы выполняете доступ за пределы границ при выполнении
a[y].push_back(x-1); // a[y][last] = -1
...
int u = a[i][j];
dp[i] = max(dp[i], dp[u] + i - u); // dp[u] = dp[-1]
Доступ за пределами границ - это неопределенное поведение, просто случилось сбой с -O0
и сбой с -O2
, вероятно, из-за разного расположения глобальных переменных.
вы можете обнаружить эту ошибку с помощью утверждения.
assert(u >= 0 && u < maxn);
в качестве альтернативы вы можете использовать std::array<int,maxn> dp;
и надеяться, что ваша стандартная библиотека имеет утверждения для оператора скобки в режиме отладки, как это делает MSVC.
Поскольку вы начинаете цикл через dp
с 1, вы вычитаете 1 из x
, и любые 0, которые вы читаете, становятся -1, что является недопустимыми индексами.
Вы можете это исправить, выполнив цикл с 0. Я использовал std::vector::at
при первом доступе к индексу, потому что он проверен. Переключение на std::vector
также означает, что вещи подходящего размера.
Н.б. Гораздо лучше объявлять переменные в момент их инициализации или сразу же при чтении из ввода.
int main() {
freopen("demo.txt", "r", stdin);
freopen("demo2.out", "w", stdout);
int n, maxy = -1;
if (scanf("%d", &n) != 1) return 1;
std::vector<std::vector<int>> a(n);
for (int i = 0; i < n; i++) {
int x, y;
if (std::scanf("%d %d", &x, &y) != 2) return 2;
a.at(y).push_back(x);
maxy = std::max(maxy, y);
}
std::vector<int> dp(maxy + 1);
int prev = 0;
for (int i = 0; i <= maxy; i++) {
int& dpi = dp[i];
dpi = prev;
for (int u : a[i]) {
dpi = std::max(dpi, dp.at(u) + i - u);
}
prev = dpi;
}
printf("%d\n", dp.back());
}
Вы пробовали запустить его с дезинфицирующим средством, просто чтобы проверить неопределенное поведение?