题目不难,是最短路径的变形。大致题意为:
给定n个顶点,以及m条边的描述,每条边的描述包括:起点、终点、权重。现在要从顶点1出发到达顶点n,求路径中能够承受的最大权重。
首先题目的理解非常重要。本题要求出的是从顶点1到顶点n的所有可行路径中各边权值的最小值的最大值。即max(min(可行路径边))。很显然是最短路径的变形。这里给出两个思路。
首先贪心思想:模仿Dijkstra算法 O(n^2)
令dis[i]表示从顶点1到顶点i的可行路径中各边权值的最小值的最大值。
则我们可以模仿Dijkstra算法,先求出最大的dis值,然后依据已经求出的dis值来扩展其余点的dis值,最终1到其余所有点的dis值。那么应该如何扩展捏?可以从dis的定义出发,要求出所有可行路径中各权值的最小值的最大值,那么若能扩展,则必有min{dis[i],trim[i][j]}>dis[j],即可以找到一条边权值更大的可行路径。同时由于是求最大值,则初始化时要注意点之间的距离要为负无穷。
其次是dp思想:模仿floyd算法 O(n^3)
令dis[i][j]表示从顶点i到顶点j的各可行路径中各边权值的最小值的最大值。那么假设有顶点k序列,满足:i与k序列相连,k序列与j相连。则从i到j就有了一条可行路径:i——k序列——j。而这条路径的最短边为min(dis[i][k],dis[k][j]},于是dis[i][j]应该为所有这些边中的最大值。于是动态转移方程为:
dp[i][j]=Max{dis[i][j],min{dis[i][k],dis[k][j]}}
下面为代码:4132K+375MS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define Max 1010
#define Maxx(a,b) (a)>(b)?(a):(b)
#define Min(a,b) (a)<(b)?(a):(b)
#define Inf 100000010
int trim[Max][Max]; //邻接矩阵
int dis[Max]; //从点1到其余各点的可行路径上边权值最小值的最大值
bool vis[Max];//标记是否已经求出dis
int Case,n,m; //情况数、点个数、边个数
void Dijkstra(){//dijkstra算法求从点1到其余各点的可行路径上边权值最小值的最大值
int i,j;
memset(vis,0,sizeof(vis)); //初始化为均未求出dis值
dis[1]=0; //初始化1到1最大值为0
vis[1]=true;//标记1已经求出dis值
for(i=2;i<=n;i++) //初始化为边权值,注意若边实际不存在则其值为负无穷,在主函数中初始化
dis[i]=trim[1][i];
int maxint,ind;
for(i=1;i<n;i++){ // 循环n-1次,求出每个顶点的dis值
maxint=-Inf,ind=1; // 初始化为负无穷、并入顶点为1
for(j=1;j<=n;j++)// 求出最大的dis值
if(!vis[j] && dis[j]>maxint){
maxint=dis[j];
ind=j;
}
vis[ind]=true; // 标记为已经求出,并入求出顶点集合
for(j=1;j<=n;j++) //扩展各顶点
if(!vis[j] && (Min(dis[ind],trim[ind][j]))>dis[j])//扩展条件
dis[j]=Min(dis[ind],trim[ind][j]);
}
printf("%d\n\n",dis[n]); //输出最大值,注意有两个空行
}
int main(){
int i,j,a,b,w;
scanf("%d",&Case);
for(int k=1;k<=Case;k++){
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)//初始化为负无穷
for(j=1;j<=n;j++)
trim[i][j]=-Inf;
while(m--){ //输入边的信息
scanf("%d%d%d",&a,&b,&w);
trim[a][b]=trim[b][a]=w; //构造邻接矩阵
}
printf("Scenario #%d:\n",k); //输出
Dijkstra();
}
return 0;
}
下面是dp TLE代码(仅供参考)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define Max 1010
#define Maxx(a,b) (a)>(b)?(a):(b)
#define Min(a,b) (a)<(b)?(a):(b)
#define Inf 100000010
int trim[Max][Max];
bool flag[Max][Max];
int dis[Max][Max];
int Case,n,m;
void floyd(){
int i,j,k;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i==j)
dis[i][j]=0;
else
dis[i][j]=trim[i][j];
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
dis[i][j]=Maxx(dis[i][j],Min(dis[i][k],dis[k][j]));
printf("%d\n\n",dis[1][n]);
}
int main(){
int i,j,a,b,w;
scanf("%d",&Case);
for(int k=1;k<=Case;k++){
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
trim[i][j]=-Inf;
memset(flag,0,sizeof(flag));
while(m--){
scanf("%d%d%d",&a,&b,&w);
trim[a][b]=trim[b][a]=w;
}
printf("Scenario #%d:\n",k);
floyd();
}
return 0;
}