思路:最短路+优先队列+Dijstra+枚举边
分析:
1 题目要求的是删掉一条边之和求出的最短路中的最大值。
2 很明显,肯定是要先求出原图的最短路并且记录父亲节点。现在我们可以想,如果要枚举所有的边,显然这个是不可能的实现的。所以我们仔细分析可以知道其实能够对最短路产生影响的就是原图最短路上的边,所以我们只需要去枚举删除最短路径上面边然后求最短路即可,最后得到ans
3 这一题的n <= 1000 , m<=n*(n-1)/2 , 刚开始我用的SPFA,然后就开始TLE。后来知道了,有些时候SPFA的期望值中O(ke),有些题目会卡k,所以这个时候只能选择优先队列的Dij算法了。
4 题目用到了捆绑两种类型的pair<int , int>pii;
代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<utility> #include<queue> using namespace std; #define MAXN 2010 #define INF 0xFFFFFFF typedef pair<int , int>pii; int n , m; int value[MAXN][MAXN]; int tmpFather[MAXN]; int father[MAXN]; int dis[MAXN]; int vis[MAXN]; priority_queue<pii , vector<pii> , greater<pii> >q;/*创建一个优先队列,并且声明为小整数*/ /*初始化*/ void init(){ for(int i = 1 ; i <= n ; i++){ for(int j = 1 ; j <= n ; j++) value[i][j] = INF; value[i][i] = 0; } } void Dij(int s){ memset(vis , 0 , sizeof(vis)); for(int i = 2 ; i <= n ; i++) dis[i] = INF; dis[s] = 0; q.push(make_pair(dis[s] , s)); while(!q.empty()){ pii u = q.top(); q.pop(); int x = u.second;/*x为点*/ if(vis[x]) continue; vis[x] = 1; for(int i = 1 ; i <= n ; i++){ if(dis[i] > dis[x] + value[x][i]){ dis[i] = dis[x] + value[x][i]; father[i] = x;/*记录父亲*/ q.push(make_pair(dis[i] , i));/*插入队列*/ } } } } int main(){ int a , b , v , tmp_v , ans; while(scanf("%d%d" , &n , &m) != EOF){ init(); for(int i = 0 ; i < m ; i++){ scanf("%d%d%d" , &a , &b , &v); if(value[a][b] > v) value[a][b] = value[b][a] = v; } Dij(1); a = n; ans = 0; memcpy(tmpFather , father , sizeof(father));/*数组复制*/ while(1){/*枚举要删除的边*/ b = tmpFather[a]; tmp_v = value[a][b]; value[a][b] = value[b][a] = INF; Dij(1); if(ans < dis[n]) ans = dis[n]; value[a][b] = value[b][a] = tmp_v; a = tmpFather[a]; if(a == 1) break; } printf("%d\n" , ans); } return 0; }