大意:给你个图,让你找一个从起点到终点,最小边的最大值的路径,然后把与这些路径上的点相连的非路径边给删除掉,然后输出这些边的编号;
- 怎么找这个最小边的最大值?
当前这个点到起点的所有路径中,每一条路径上都有最小边值,
把这条边和其他路径上的最小边比较留最大的,即最小边最大化; - 具体怎么实现?
设dis[u]为起点到u点的最小边最大值,w[i]为点u,v的边权
从起点到u,再到v的这条路的最小边最大值为:dis[v]=min(dis[u],w[i]);
但能到点v的不止uv这条边,所以dis[v]=max(dis[v],min(dis[u],w[i]); - 为什么 dis[v]=min(dis[u],w[i])
(1). 假如w[i]>dis[u],即它比从起点到u的每一条路径上的最小边都大
所以它都没资格成为某条路径上的最小边,没法和dis[u]竞争,所以选小的dis[u].
(2).假如w[i]<dis[u],即他现在成为最小边比他大的路径新的最小边了,
他把比他大的都换下去了,他不就成为现在最大的了嘛,所以选小的w[i]; - 用spfa的思想,进行缩边,并储存路径
- 根据题目要求删边然后输出
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10,M=2*N,INF=0x3f3f3f3f;
int n,m;
int head[N],ne[M],ue[M],ve[M],w[M],cnt;
queue<int> qu; //spfa所用的队列
bool vis[N]; //判断是否在队列
int pre[N]; //记录路径
int dis[N]; //不再表示最短路,而是 从起点到i点的最小边的最大值
queue<int> ans;
void add(int a,int b,int c){
ue[cnt]=a;
ve[cnt]=b;
w[cnt]=c;
ne[cnt]=head[a];
head[a]=cnt++;
}
void spfa(){
qu.push(0);
vis[0]=1;
dis[0]=INF;//初始化为最大值,才能更新某一条路径的最小边;
int u,v;
while(!qu.empty()){
u=qu.front();
qu.pop();
vis[u]=0;
for(int i=head[u];i!=-1;i=ne[i]){
v=ve[i];
// dis[v]=max(dis[v],min(dis[u],w[i]);
if(dis[v]<min(dis[u],w[i])){
dis[v]=min(dis[u],w[i]);
pre[v]=u;
if(vis[v]==0){
vis[v]=1;
qu.push(v);
}
}
}
}
}
void init(){
for(int i=0;i<n;i++) head[i]=-1,pre[i]=-1;
}
int main(){
cin>>n>>m;
init();
//因为每个边都有编号,所以用数组模拟邻接矩阵,能直接通过下标访问
//又因为图是无向图,所以边的编号是下标除二;
int a,b,c;
for(int i=1;i<=m;i++){
cin>>a>>b>>c;
add(a,b,c);
add(b,a,c);
}
spfa();//spfa变形找最小边的最大值,并记录路径
for(int e=n-1;e!=-1;e=pre[e]){
vis[e]=1;
if(e==0) break;
}
for(int i=0;i<cnt;i+=2){
if(vis[ue[i]]==1&&vis[ve[i]]==0||vis[ue[i]]==0&&vis[ve[i]]==1){
ans.push(i/2);
}
else if(vis[ue[i]]==1&&vis[ve[i]]==1&&pre[ue[i]]!=ve[i]&&pre[ve[i]]!=ue[i]){
ans.push(i/2);
}
}
if(ans.empty()) cout<<"none";
while(!ans.empty()){
cout<<ans.front()<<" ";
ans.pop();
}
return 0;
}