从控制台和文件读取相同数据时Dijkstra程序运行结果不一致
Dijkstra算法文件读取异常问题解决
我实现的Dijkstra算法C代码在控制台粘贴输入时能得到正确结果1559,但取消freopen注释读取文件时输出0。输入数据有6000+行,运行环境为Windows 10,编译命令g++ a.cpp -o a.exe -Wall,C11标准。
原代码:
#include <cstdio> using namespace std; int mp[2505][2505]; int n, m, s, t; const int INF = INT_MAX/4; int main() { // freopen(".\\IO\\stdin.in", "r", stdin); for (int i=0; i<2505; i++) for (int j=0; j<2505; j++) mp[i][j] = i==j ? 0 : INF; scanf("%d%d%d%d", &n, &m, &s, &t); for (int i=0; i<m; i++) { int u, v, t; scanf("%d%d%d", &u, &v, &t); mp[u][v] = mp[v][u] = t; } int dis[3000]; for (int i=1; i<=n; i++) dis[i] = INF; dis[s] = 0; bool walked[2505]; memset(walked, 0, sizeof(walked)); for (int i=1; i<=n; i++) { int minN = -1, minV = INF; for (int j=1; j<=n; j++) { if (walked[j]) continue; if (dis[j] < minV) minV=dis[j], minN=j; } for (int p=1; p<=n; p++) if (dis[minN] + mp[minN][p] < dis[p]) dis[p] = dis[minN] + mp[minN][p]; walked[minN] = 1; } printf("%d\n", dis[t]); return 0; }
问题根源
路径转义错误:
Windows系统中路径分隔符是\,但在C++字符串中\是转义字符,需要用\\表示实际的\。原代码中的".\IO\stdin.in"会被编译器解析为".IOstdin.in"(因为\I和\s是无效转义序列,编译器会忽略转义符直接保留后续字符),导致freopen无法找到目标文件。未检查文件打开状态:
freopen打开失败时会返回NULL,但代码没有做任何判断。此时后续的scanf会读取失败,全局变量n、m、s、t会保持默认的0值,最终输出dis[0]的未初始化值(恰好为0)。变量命名冲突(潜在问题):
循环内的局部变量t与全局变量t(目标节点)重名,虽然当前未直接引发问题,但会降低代码可读性,容易引发后续逻辑错误。
修正方案
- 修正路径写法:使用
".\\IO\\stdin.in"(双反斜杠)或"./IO/stdin.in"(正斜杠,Windows系统兼容)。 - 添加文件打开失败的判断逻辑,避免后续错误执行。
- 重命名局部变量
t为weight(或其他名称),消除命名冲突。
修正后的代码:
#include <cstdio> #include <cstdlib> // 用于exit() using namespace std; int mp[2505][2505]; int n, m, s, t; const int INF = INT_MAX/4; int main() { // 使用双反斜杠转义路径,或改用正斜杠 if (freopen(".\\IO\\stdin.in", "r", stdin) == NULL) { printf("Failed to open file!\n"); exit(1); } for (int i=0; i<2505; i++) for (int j=0; j<2505; j++) mp[i][j] = i==j ? 0 : INF; scanf("%d%d%d%d", &n, &m, &s, &t); for (int i=0; i<m; i++) { int u, v, weight; // 重命名避免冲突 scanf("%d%d%d", &u, &v, &weight); mp[u][v] = mp[v][u] = weight; } int dis[3000]; for (int i=1; i<=n; i++) dis[i] = INF; dis[s] = 0; bool walked[2505]; memset(walked, 0, sizeof(walked)); for (int i=1; i<=n; i++) { int minN = -1, minV = INF; for (int j=1; j<=n; j++) { if (walked[j]) continue; if (dis[j] < minV) minV=dis[j], minN=j; } // 处理无法找到有效节点的情况(避免minN为-1导致数组越界) if (minN == -1) break; for (int p=1; p<=n; p++) if (dis[minN] + mp[minN][p] < dis[p]) dis[p] = dis[minN] + mp[minN][p]; walked[minN] = 1; } printf("%d\n", dis[t]); return 0; }
额外说明:
- 新增了
minN == -1的判断,避免当图不连通时出现数组越界访问的问题,提升代码健壮性。 - 使用
exit(1)在文件打开失败时终止程序,防止后续逻辑基于无效数据执行。
内容的提问来源于stack exchange,提问作者EchoInVoid
相关产品推荐
相关产品推荐

