luogu P1186玛丽卡
题目描述
麦克找了个新女朋友,玛丽卡对他非常恼火并伺机报复。
因为她和他们不住在同一个城市,因此她开始准备她的长途旅行。
在这个国家中每两个城市之间最多只有一条路相通,并且我们知道从一个城市到另一个城市路上所需花费的时间。
麦克在车中无意中听到有一条路正在维修,并且那儿正堵车,但没听清楚到底是哪一条路。无论哪一条路正在维修,从玛丽卡所在的城市都能到达麦克所在的城市。
玛丽卡将只从不堵车的路上通过,并且她将按最短路线行车。麦克希望知道在最糟糕的情况下玛丽卡到达他所在的城市需要多长时间,这样他就能保证他的女朋友离开该城市足够远。
编写程序,帮助麦克找出玛丽卡按最短路线通过不堵车道路到达他所在城市所需的最长时间(用分钟表示)。
输入输出格式
输入格式:
第一行有两个用空格隔开的数N和M,分别表示城市的数量以及城市间道路的数量。1≤N≤1000,1≤M≤N*(N-1)/2。城市用数字1至N标识,麦克在城市1中,玛丽卡在城市N中。
接下来的M行中每行包含三个用空格隔开的数A,B和V。其中1≤A,B≤N,1≤V≤1000。这些数字表示在A和城市B中间有一条双行道,并且在V分钟内是就能通过。
输出格式:
输出文件的第一行中写出用分钟表示的最长时间,在这段时间中,无论哪条路在堵车,玛丽卡应该能够到达麦克处,如果少于这个时间的话,则必定存在一条路,该条路一旦堵车,玛丽卡就不能够赶到麦克处。
输入输出样例
输入样例#1:
5 7 1 2 8 1 4 10 2 3 9 2 4 10 2 5 1 3 4 7 3 5 10
输出样例#1:
27
直接暴力枚举每条边不能走取最小(TLE5):
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<queue> 5 6 using namespace std; 7 const int N=1010; 8 const int Maxn=99999999; 9 10 int head[N]; 11 int dis[N]; 12 bool vis[N]; 13 int now=1; 14 queue<int>q; 15 int n,m; 16 int x,y; 17 18 struct node{ 19 int u,v,w,nxt; 20 }E[N*(N-1)/2]; 21 22 inline int read() 23 { 24 int x=0; 25 char c=getchar(); 26 while(c<'0'||c>'9')c=getchar(); 27 while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar(); 28 return x; 29 } 30 31 inline void add(int u,int v,int w) 32 { 33 E[now].u=u; 34 E[now].v=v; 35 E[now].w=w; 36 E[now].nxt=head[u]; 37 head[u]=now++; 38 } 39 40 inline void spfa(int start) 41 { 42 for(int i=1;i<=n;i++) 43 dis[i]=Maxn; 44 dis[start]=0; 45 vis[start]=1; 46 q.push(start); 47 while(!q.empty()) 48 { 49 int top=q.front(); 50 q.pop(); 51 vis[top]=0; 52 for(int i=head[top];i!=-1;i=E[i].nxt) 53 { 54 int u=E[i].u,v=E[i].v; 55 if((u!=x&&u!=y)||(v!=x&&v!=y)) 56 if(dis[v]>dis[u]+E[i].w) 57 { 58 dis[v]=dis[u]+E[i].w; 59 if(!vis[v]) 60 { 61 vis[v]=1; 62 q.push(v); 63 } 64 } 65 } 66 } 67 } 68 69 int main() 70 { 71 n=read(); 72 m=read(); 73 for(int i=1;i<=n;i++) 74 head[i]=-1; 75 for(int i=1;i<=m;i++) 76 { 77 int u=read(),v=read(),w=read(); 78 add(u,v,w); 79 add(v,u,w); 80 } 81 int answer=-1; 82 for(int i=1;i<=2*m;i++) 83 { 84 x=E[i].u; 85 y=E[i].v; 86 spfa(1); 87 answer=max(answer,dis[n]); 88 } 89 printf("%d",answer); 90 return 0; 91 }
后来通过画图发现,上述方法多枚举了较多条无用边,可以先求出最短路,枚举每一条最短路上的边:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<queue> 5 6 using namespace std; 7 const int N=1010; 8 const int Maxn=99999999; 9 10 int head[N]; 11 int dis[N]; 12 bool vis[N]; 13 int fa[N]; 14 int now=1; 15 queue<int>q; 16 int n,m; 17 int x,y; 18 19 struct node{ 20 int u,v,w,nxt; 21 }E[N*(N-1)]; 22 23 inline int read() 24 { 25 int x=0; 26 char c=getchar(); 27 while(c<'0'||c>'9')c=getchar(); 28 while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar(); 29 return x; 30 } 31 32 inline void add(int u,int v,int w) 33 { 34 E[now].u=u; 35 E[now].v=v; 36 E[now].w=w; 37 E[now].nxt=head[u]; 38 head[u]=now++; 39 } 40 41 inline void spfa(int start,bool flag) 42 { 43 for(int i=1;i<=n;i++) 44 dis[i]=Maxn,vis[i]=0; 45 dis[start]=0; 46 vis[start]=1; 47 q.push(start); 48 while(!q.empty()) 49 { 50 int top=q.front(); 51 q.pop(); 52 vis[top]=0; 53 for(int i=head[top];i!=-1;i=E[i].nxt) 54 { 55 int u=E[i].u,v=E[i].v; 56 if(!flag&&((u!=x&&u!=y)||(v!=x&&v!=y))&&(dis[v]>dis[u]+E[i].w)) 57 { 58 dis[v]=dis[u]+E[i].w; 59 if(!vis[v]) 60 { 61 vis[v]=1; 62 q.push(v); 63 } 64 } 65 if(flag&&dis[v]>dis[u]+E[i].w) 66 { 67 dis[v]=dis[u]+E[i].w; 68 fa[E[i].v]=E[i].u; 69 if(!vis[v]) 70 { 71 vis[v]=1; 72 q.push(v); 73 } 74 } 75 } 76 } 77 } 78 79 int main() 80 { 81 n=read(); 82 m=read(); 83 84 for(int i=1;i<=n;i++) 85 head[i]=-1; 86 for(int i=1;i<=m;i++) 87 { 88 int u=read(),v=read(),w=read(); 89 add(u,v,w); 90 add(v,u,w); 91 } 92 93 spfa(1,true); 94 int answer=-1; 95 int i=n; 96 while(fa[i]>=1) 97 { 98 x=i; 99 y=fa[i]; 100 spfa(1,false); 101 answer=max(answer,dis[n]); 102 i=fa[i]; 103 } 104 printf("%d",answer); 105 return 0; 106 }