证明:这个版本的证明比较简洁易懂
问题:
状
态
表
示
:
d
[
i
]
:
从
1
−
i
的
路
径
上
的
最
大
边
权
的
最
小
值
状态表示:d[i]:从1-i的路径上的最大边权的最小值
状态表示:d[i]:从1−i的路径上的最大边权的最小值
状
态
转
移
:
d
[
v
]
=
m
i
n
(
d
[
v
]
,
m
a
x
(
d
[
v
]
,
w
)
)
假
设
当
前
弹
出
的
顶
点
是
u
,
且
u
与
v
的
临
接
边
是
w
状态转移:d[v]=min(d[v],max(d[v],w))\\假设当前弹出的顶点是u,且u与v的临接边是w
状态转移:d[v]=min(d[v],max(d[v],w))假设当前弹出的顶点是u,且u与v的临接边是w
正
确
性
证
明
:
建
立
最
小
堆
,
假
设
当
前
的
集
合
是
S
,
弹
出
的
顶
点
是
u
,
只
需
证
明
d
[
u
]
之
后
不
会
被
更
新
即
可
。
采
用
反
证
法
,
假
设
存
在
一
个
顶
点
t
,
且
t
∉
S
∪
u
,
m
a
x
(
d
[
t
]
,
w
(
t
,
u
)
)
<
d
[
u
]
。
由
算
法
的
步
骤
我
们
知
道
,
d
[
t
]
>
=
d
[
u
]
,
故
m
a
x
(
d
[
t
]
,
w
(
t
,
u
)
)
>
=
d
[
u
]
,
与
之
前
的
假
设
矛
盾
,
故
说
明
该
算
法
正
确
正确性证明:建立最小堆,假设当前的集合是S,弹出的顶点是u,只需证明d[u]之后不会被更新即可。采用反证法,假设存在一个顶点 \\t,且t\notin S\cup u,max(d[t],w(t,u))<d[u]。由算法的步骤我们知道,d[t]>=d[u],故\\max(d[t],w(t,u))>=d[u],与之前的假设矛盾,故说明该算法正确
正确性证明:建立最小堆,假设当前的集合是S,弹出的顶点是u,只需证明d[u]之后不会被更新即可。采用反证法,假设存在一个顶点t,且t∈/S∪u,max(d[t],w(t,u))<d[u]。由算法的步骤我们知道,d[t]>=d[u],故max(d[t],w(t,u))>=d[u],与之前的假设矛盾,故说明该算法正确
代 码 : 代码: 代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5 * 100000 + 5;
#define pii pair<int,int>
vector<pii>to[N];
int d[N];
bool vis[N];
int n, m;
void add(int a, int b, int c)
{
to[a].push_back({ b,c });
}
void dijkstra()
{
memset(d, 0x3f, sizeof d);
priority_queue<pii, vector<pii>, greater<pii>>q;
q.push({ 0,1 });
d[1] = 0;
while (!q.empty())
{
auto t = q.top();
q.pop();
int v = t.second;
if (vis[v])
{
continue;
}
vis[v] = true;
for (auto& i : to[v])
{
int j = i.first;
int w = i.second;
if (max(d[v],w)<d[j])
{
d[j] = max(d[v], w);
q.push({ d[j],j });
}
}
}
cout << d[n];
}
signed main()
{
cin >> n >> m;
for (int i = 0; i < m; i++)
{
int a, b, c;
cin >> a >> b >> c;
add(a, b, c);
add(b, a, c);
}
dijkstra();
return 0;
}