HDU1595
HDU3986
题意:每删除一条边,可能会有一条从1到n的最短路,求最长的最短路。
题解:hdu1596有重边,hdu3986无重边。
枚举每一条边,太暴力了,肯定TLE。
那枚举哪些边好呢?显然是在没有cut边之前的最短路上的边。
why?因为非最短路的边,删去了对最短路没有影响。
第一次Dijkstra记录最短路上所有的边,然后每次去掉一条边,Dijkstra一波
HDU1596代码:领接表。朴素的dijkstra有重边,无法记录。
#include <bits/stdc++.h>
using namespace std;
int const inf = 0x7f7f7f7f;
int const N = 1000 + 10;
int const M = 100000 + 10;
int first[N],ne[M],to[M],w[M],from[M],tot;
int dis[N],vis[N],n,m,last[N];
void add(int u,int v,int d){
ne[++tot] = first[u];
from[tot] = u;
to[tot] = v;
w[tot] = d;
first[u] = tot;
}
struct Node
{
int u,len;
Node(int a,int b):u(a),len(b){};
bool operator < (const Node &x) const{
return len > x.len;
}
};
priority_queue<Node>q;
void Dijkstra(int t,bool flag){
for(int i=1;i<=n;i++) dis[i] = inf;
dis[1] = 0;
q.push(Node(1,0));
while(!q.empty()){
Node p = q.top(); q.pop();
int u = p.u;
if(dis[u] < p.len) continue;
for(int i=first[u];i;i=ne[i]){
if(i == t) continue;
int v = to[i], dist = w[i];
if(dis[v] > dis[u] + dist){
if(flag) last[v] =i;
dis[v] = dis[u] + dist;
q.push(Node(v,dis[v]));
}
}
}
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
tot = 0;
memset(first,0,sizeof(first));
for(int i=1;i<=m;i++){
int u,v,d;
scanf("%d%d%d",&u,&v,&d);
add(u,v,d); add(v,u,d); //有重变
}
Dijkstra(0,1);
if(dis[n] == inf){
printf("%d\n",-1);
continue;
}
int ans = 0,edge;
for(int i=n;i;i=from[edge]){
edge = last[i];
Dijkstra(edge,0);
ans = max(ans,dis[n]);
}
if(ans == inf) printf("%d\n",-1);
else printf("%d\n",ans);
}
}
HDU3986代码:上面的代码依然可行。另外来一个朴素Dijkstra
#include <bits/stdc++.h>
using namespace std;
int const inf = 0x7f7f7f7f;
int const N = 1000 + 10;
int n,m,last[N],mp[N][N],vis[N],dis[N];
void Dijkstra(int flag){
for(int i=1;i<=n;i++) dis[i] = inf,vis[i] = false;
dis[1] = 0;
for(int i=1;i<n;i++){
int MIN = inf,u;
for(int j=1;j<=n;j++)
if(!vis[j]&&dis[j]<MIN)
MIN = dis[j],u = j;
if(MIN == inf) return;
vis[u] = true;
for(int j=1;j<=n;j++){
if(!vis[j] && mp[u][j] != inf && dis[u]+mp[u][j]<dis[j]){
dis[j] = dis[u] + mp[u][j];
if(flag) last[j] = u;
}
}
}
}
int main(){
while(~scanf("%d%d",&n,&m)){
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
if(i == j) mp[i][j] = 0;
else mp[i][j] = inf;
}
for(int i=1;i<=m;i++){
int u,v,d;
scanf("%d%d%d",&u,&v,&d);
if(mp[u][v] > d)
mp[u][v] = mp[v][u] = d;
}
Dijkstra(1);
int ans = -inf;
for(int i=n;i!=1;i=last[i]){
int p1 = i, p2 = last[i];
int tmp = mp[p1][p2];
mp[p1][p2] = mp[p2][p1] = inf;
Dijkstra(0);
ans = max(ans,dis[n]);
mp[p1][p2] = mp[p2][p1] = tmp;
}
printf("%d\n",ans);
}
}
本来想用非邻接表的FIFO优化的版本,但是一直TLE,等我写出来再贴。