题解:洛谷 P1111 修复公路

【题目来源】

洛谷:P1111 修复公路 - 洛谷

【题目描述】

给出 A 地区的村庄数 \(N\),和公路数 \(M\),公路是双向的。并告诉你每条公路的连着哪两个村庄,并告诉你什么时候能修完这条公路。问最早什么时候任意两个村庄能够通车,即最早什么时候任意两条村庄都存在至少一条修复完成的道路(可以由多条公路连成一条道路)。

【输入】

\(1\) 行两个正整数 \(N,M\)

下面 \(M\) 行,每行 \(3\) 个正整数 \(x,y,t\),告诉你这条公路连着 \(x,y\) 两个村庄,在时间 \(t\) 时能修复完成这条公路。

【输出】

如果全部公路修复完毕仍然存在两个村庄无法通车,则输出 \(-1\),否则输出最早什么时候任意两个村庄能够通车。

【输入样例】

4 4
1 2 6
1 3 4
1 4 5
4 2 3

【输出样例】

5

【算法标签】

《洛谷 P1111 修复公路》 #二分# #并查集# #排序# #生成树#

【代码详解】

#include <bits/stdc++.h>
using namespace std;
const int N = 1005, M = 100005;
int n, m, u, v, t, mid;
struct Edge
{
    int u, v, t;  // 边的起点、终点、通过时间
}e[100005];
vector<int> ve[N];  // 邻接表
bool flag, vis[N];  // flag标记是否有解,vis标记是否访问过

// 初始化函数,根据当前mid值构建图
void init()
{
    // 清空邻接表
    for (int i=1; i<=n; i++)
    {
        ve[i].clear();
    }
    
    // 重置访问标记
    memset(vis, 0, sizeof(vis));
    
    // 只添加通过时间小于等于mid的边
    for (int i=1; i<=m; i++)
    {
        if (e[i].t<=mid)
        {
            // 添加无向边
            ve[e[i].u].push_back(e[i].v);
            ve[e[i].v].push_back(e[i].u);
        }
    }
}

// 深度优先搜索
void dfs(int x)
{
    vis[x] = 1;  // 标记当前节点已访问
    
    // 遍历当前节点的所有邻居
    for (int i=0; i<ve[x].size(); i++)
    {
        int tmp_v = ve[x][i];
        if (vis[tmp_v]) continue;  // 如果邻居已访问,跳过
        dfs(tmp_v);  // 递归访问邻居
    }
}

// 检查图是否连通
bool check()
{
    // 检查所有节点是否都被访问过
    for (int i=1; i<=n; i++)
    {
        if (vis[i]==0)
        {
            return false;  // 有节点未访问,图不连通
        }
    }
    return true;  // 所有节点都已访问,图连通
}

int main()
{
    cin >> n >> m;  // 读入节点数和边数
    
    // 读入所有边的信息
    for (int i=1; i<=m; i++)
    {
        cin >> e[i].u >> e[i].v >> e[i].t;
    } 
    
    int l = 1, r = 100000;  // 二分查找的最小和最大通过时间
    
    // 二分查找满足条件的最小通过时间
    while (l<r)
    {
        mid = (l+r)/2;  // 计算中间值
        init();  // 根据mid值初始化图
        dfs(1);  // 从节点1开始深度优先搜索
        
        if (check())  // 如果图是连通的
        {
            r = mid;  // 尝试更小的时间
            flag = true;  // 标记有解
        }
        else  // 如果图不连通
        {
            l = mid + 1;  // 需要更大的时间
        }
    }
    
    // 输出结果
    if (flag) 
    {
        cout << l << endl;  // 输出最小通过时间
    }
    else 
    {
        cout << -1 << endl;  // 无解
    }
    return 0;
}

【运行结果】

4 4
1 2 6
1 3 4
1 4 5
4 2 3
5
posted @ 2026-03-14 21:50  团爸讲算法  阅读(1)  评论(0)    收藏  举报