题解:洛谷 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
浙公网安备 33010602011771号