You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从控制台和文件读取相同数据时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;
}

问题根源

  1. 路径转义错误:
    Windows系统中路径分隔符是\,但在C++字符串中\是转义字符,需要用\\表示实际的\。原代码中的".\IO\stdin.in"会被编译器解析为".IOstdin.in"(因为\I和\s是无效转义序列,编译器会忽略转义符直接保留后续字符),导致freopen无法找到目标文件。

  2. 未检查文件打开状态:
    freopen打开失败时会返回NULL,但代码没有做任何判断。此时后续的scanf会读取失败,全局变量n、m、s、t会保持默认的0值,最终输出dis[0]的未初始化值(恰好为0)。

  3. 变量命名冲突(潜在问题):
    循环内的局部变量t与全局变量t(目标节点)重名,虽然当前未直接引发问题,但会降低代码可读性,容易引发后续逻辑错误。

修正方案

  1. 修正路径写法:使用".\\IO\\stdin.in"(双反斜杠)或"./IO/stdin.in"(正斜杠,Windows系统兼容)。
  2. 添加文件打开失败的判断逻辑,避免后续错误执行。
  3. 重命名局部变量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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 20:38:14