Luogu P1186 玛丽卡 【最短路】By cellur925
题目描述
麦克找了个新女朋友,玛丽卡对他非常恼火并伺机报复。
因为她和他们不住在同一个城市,因此她开始准备她的长途旅行。
在这个国家中每两个城市之间最多只有一条路相通,并且我们知道从一个城市到另一个城市路上所需花费的时间。
麦克在车中无意中听到有一条路正在维修,并且那儿正堵车,但没听清楚到底是哪一条路。无论哪一条路正在维修,从玛丽卡所在的城市都能到达麦克所在的城市。
玛丽卡将只从不堵车的路上通过,并且她将按最短路线行车。麦克希望知道在最糟糕的情况下玛丽卡到达他所在的城市需要多长时间,这样他就能保证他的女朋友离开该城市足够远。
编写程序,帮助麦克找出玛丽卡按最短路线通过不堵车道路到达他所在城市所需的最长时间(用分钟表示)。
输入输出格式
输入格式:
第一行有两个用空格隔开的数 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分钟内是就能通过。
输出格式:
一行,写出用分钟表示的最长时间,在这段时间中,无论哪条路在堵车,玛丽卡应该能够到达麦克处,如果少于这个时间的话,则必定存在一条路,该条路一旦堵车,玛丽卡就不能够赶到麦克处。
输入输出样例
5 7 1 2 8 1 4 10 2 3 9 2 4 10 2 5 1 3 4 7 3 5 10
27
两A海星...
题意说的繁复冗杂,看了很久才明白意思。
一句话题意:
于是就想:既然每次只有一条路堵车,那我们就可以枚举会堵车的路,把它删去,更新更大的答案。略微算了一下:复杂度可能要爆炸了。于是又
想:那这些删的边应该在1到n的最短路上吧,想了想觉得不太好写呀,于是去肝暴力删每个边的算法。
搞一搞就交,果不其然50分,TLE了5个点,我觉得布星。
1 #include<cstdio> 2 #include<algorithm> 3 #include<queue> 4 #include<cstring> 5 #define maxn 1200 6 7 using namespace std; 8 typedef long long ll; 9 10 int n,m,tot; 11 int head[maxn]; 12 ll ans,dis[maxn]; 13 bool flag[1000000],vis[maxn]; 14 struct node{ 15 int val,to,next; 16 }edge[1000000]; 17 18 void add(int x,int y,int z) 19 { 20 edge[++tot].val=z; 21 edge[tot].to=y; 22 edge[tot].next=head[x]; 23 head[x]=tot; 24 } 25 26 void spfa() 27 { 28 memset(vis,0,sizeof(vis)); 29 memset(dis,0x3f,sizeof(dis)); 30 queue<int>q; 31 q.push(1),vis[1]=1,dis[1]=0; 32 while(!q.empty()) 33 { 34 int x=q.front();q.pop(); 35 vis[x]=0; 36 for(int i=head[x];i;i=edge[i].next) 37 { 38 int v=edge[i].to; 39 if(dis[v]>dis[x]+edge[i].val&&!flag[i]) 40 { 41 dis[v]=dis[x]+edge[i].val; 42 if(!vis[v]) q.push(v),vis[v]=1; 43 } 44 } 45 } 46 if(dis[n]>ans) ans=dis[n]; 47 } 48 49 int main() 50 { 51 scanf("%d%d",&n,&m); 52 for(int i=1;i<=m;i++) 53 { 54 int x=0,y=0,z=0; 55 scanf("%d%d%d",&x,&y,&z); 56 add(x,y,z); 57 add(y,x,z); 58 } 59 for(int i=1;i<=tot;i++) 60 flag[i]=1,spfa(),flag[i]=0; 61 printf("%lld",ans); 62 return 0; 63 }
怎么记录最短路上的边呢?没忍住看了题解。其实还是很简单啦,因为是单源最短路,满足最优子结构性(所有最短路都满足),起点确定为1,而我们在跑最短路的时候松弛那一下就可以记录通往每个点的最优边序号(邻接表中)。最后我们从终点倒着跑,每次去掉最短路上的一条边,就可以枚举出最佳答案。
Tips:参照gay涛的做法,我们删边就可以把这条边的权值赋为无穷大,跑完后再修复,这是个不错的方法。
code
1 #include<cstdio> 2 #include<algorithm> 3 #include<queue> 4 #include<cstring> 5 #define maxn 1200 6 7 using namespace std; 8 typedef long long ll; 9 const int inf=0x3f3f3f3f; 10 11 int n,m,tot; 12 int head[maxn],pre[1000000]; 13 ll ans,dis[maxn]; 14 bool flag[1000000],vis[maxn]; 15 struct node{ 16 int val,to,next,last; 17 }edge[1000000]; 18 19 void add(int x,int y,int z) 20 { 21 edge[++tot].val=z; 22 edge[tot].last=x; 23 edge[tot].to=y; 24 edge[tot].next=head[x]; 25 head[x]=tot; 26 } 27 28 void spfa_pre() 29 { 30 memset(dis,0x3f,sizeof(dis)); 31 queue<int>q; 32 q.push(1),vis[1]=1,dis[1]=0; 33 while(!q.empty()) 34 { 35 int x=q.front();q.pop(); 36 vis[x]=0; 37 for(int i=head[x];i;i=edge[i].next) 38 { 39 int v=edge[i].to; 40 if(dis[v]>dis[x]+edge[i].val) 41 { 42 dis[v]=dis[x]+edge[i].val; 43 pre[v]=i; 44 if(!vis[v]) q.push(v),vis[v]=1; 45 } 46 } 47 } 48 } 49 50 void spfa_update() 51 { 52 memset(dis,0x3f,sizeof(dis)); 53 memset(vis,0,sizeof(vis)); 54 queue<int>q; 55 q.push(1),vis[1]=1,dis[1]=0; 56 while(!q.empty()) 57 { 58 int x=q.front();q.pop(); 59 vis[x]=0; 60 for(int i=head[x];i;i=edge[i].next) 61 { 62 int v=edge[i].to; 63 if(dis[v]>dis[x]+edge[i].val) 64 { 65 dis[v]=dis[x]+edge[i].val; 66 pre[v]=i; 67 if(!vis[v]) q.push(v),vis[v]=1; 68 } 69 } 70 } 71 if(dis[n]>ans) ans=dis[n]; 72 } 73 74 int main() 75 { 76 scanf("%d%d",&n,&m); 77 for(int i=1;i<=m;i++) 78 { 79 int x=0,y=0,z=0; 80 scanf("%d%d%d",&x,&y,&z); 81 add(x,y,z); 82 add(y,x,z); 83 } 84 spfa_pre(); 85 for(int i=pre[n];i;i=pre[edge[i].last]) 86 { 87 int tmp=edge[i].val; 88 edge[i].val=inf; 89 spfa_update(); 90 edge[i].val=tmp; 91 } 92 printf("%lld",ans); 93 return 0; 94 }
*Update:这几天想要是最短路条数不止一条怎么办qwq。今天重看题面发现两点间最多有1条路径Qwq