点击打开链接hdu 3986
思路: 最短路+Dij+优先队列
分析:
1 题目要求的是删除一条之和的最坏情况,并不是删除一条边之后的最短路(WA了好久不解释)。如果都可以到n,那么输入删除一条之后的最短路径。
2 利用邻阶表+优先队列优化+Dij可以做
3 father数组记录的是在原图中的1->n的最短路径中当前这个点的前一条边的编号。
4 在邻阶表里删除一条边相当于就是边的权值变为INF
代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<utility> #include<vector> #include<queue> using namespace std; #define MAXN 110010 #define MAX 1010 #define INF 0xFFFFFFF typedef pair<int , int>pii; int t , n , m; int first[MAXN] , next[MAXN]; int star[MAXN] , end[MAXN] , value[MAXN]; int vis[MAX]; int tmpFather[MAX]; int father[MAX]; int dis[MAX]; priority_queue<pii , vector<pii> , greater<pii> >q; void init(){ memset(first , -1 , sizeof(first)); memset(next , -1 , sizeof(next)); } void Dij(){ memset(vis , 0 , sizeof(vis)); for(int i = 2 ; i <= n ; i++) dis[i] = INF; dis[1] = 0; q.push(make_pair(dis[1] , 1)); while(!q.empty()){ pii u = q.top(); q.pop(); int x = u.second; if(vis[x]) continue; vis[x] = 1; for(int i = first[x] ; i != -1 ; i = next[i]){ if(dis[end[i]] > dis[x] + value[i]){ dis[end[i]] = dis[x] + value[i]; father[end[i]] = i; /*记录边的编号*/ q.push(make_pair(dis[end[i]] , end[i])); } } } } int main(){ int a , b , v , x , y , ans , tmp; scanf("%d" , &t); while(t--){ scanf("%d%d" , &n , &m); init(); for(int i = 0 ; i < m ; i++){ scanf("%d%d%d" , &star[i] , &end[i] , &value[i]); star[i+m] = end[i] , end[i+m] = star[i] , value[i+m] = value[i]; /*处理成无向图*/ next[i] = first[star[i]]; first[star[i]] = i; next[i+m] = first[star[i+m]]; first[star[i+m]] = i+m; } Dij(); if(dis[n] == INF) printf("-1\n"); else{ x = n; ans = 0; memcpy(tmpFather , father , sizeof(father)); while(1){ y = tmpFather[x]; tmp = value[y];/*保存边的值*/ value[y] = INF;/*把边删除就是相当于权值为INF*/ Dij(); value[y] = tmp; if(dis[n] == INF){/*如果这个时候不能到n说明是最坏情况,ans =-1,退出*/ ans = -1; break; } if(ans < dis[n])/*更新为*/ ans = dis[n]; x = star[y]; if(x == 1) break; } printf("%d\n" , ans); } } return 0; }