洛谷 P1119 灾后重建
来源:互联网 发布:淘宝分销商好做吗 编辑:程序博客网 时间:2024/06/07 22:47
题目背景
B地区在地震过后,所有村庄都造成了一定的损毁,而这场地震却没对公路造成什么影响。但是在村庄重建好之前,所有与未重建完成的村庄的公路均无法通车。换句话说,只有连接着两个重建完成的村庄的公路才能通车,只能到达重建完成的村庄。
题目描述
给出B地区的村庄数N,村庄编号从0到N-1,和所有M条公路的长度,公路是双向的。并给出第i个村庄重建完成的时间t[i],你可以认为是同时开始重建并在第t[i]天重建完成,并且在当天即可通车。若t[i]为0则说明地震未对此地区造成损坏,一开始就可以通车。之后有Q个询问(x, y, t),对于每个询问你要回答在第t天,从村庄x到村庄y的最短路径长度为多少。如果无法找到从x村庄到y村庄的路径,经过若干个已重建完成的村庄,或者村庄x或村庄y在第t天仍未重建完成 ,则需要返回-1。
输入格式:
输入文件rebuild.in的第一行包含两个正整数N,M,表示了村庄的数目与公路的数量。
第二行包含N个非负整数t[0], t[1], …, t[N – 1],表示了每个村庄重建完成的时间,数据保证了t[0] ≤ t[1] ≤ … ≤ t[N – 1]。
接下来M行,每行3个非负整数i, j, w,w为不超过10000的正整数,表示了有一条>连接村庄i与村庄j的道路,长度为w,保证i≠j,且对于任意一对村庄只会存在一条道路。
接下来一行也就是M+3行包含一个正整数Q,表示Q个询问。
接下来Q行,每行3个非负整数x, y, t,询问在第t天,从村庄x到村庄y的最短路径长度为多少,数据保证了t是不下降的。输出格式:
输出文件rebuild.out包含Q行,对每一个询问(x, y, t)输出对应的答案,即在第t天,从村庄x到村庄y的最短路径长度为多少。如果在第t天无法找到从x村庄到y村庄的路径,经过若干个已重建完成的村庄,或者村庄x或村庄y在第t天仍未修复完成,则输出-1。
这大概是我第一次独立A掉的提高+?
在这个特殊的日子里,我感觉我的生命在流逝 我来写博客纪念下。
不过这个题看起来挺水…
我太蒻了…
这道题求多源最短路,用floyd差不了了。
唉~不对…好像边会越来越多…
要不然加一次边跑一次spfa?
复杂度好像爆炸…
还是得用floyd…
那么只能一边加边一边跑了…
那么加一次边对那些点的最短路径有影响呢?
如果加的边val[u][v]比本来u和v的距离就大的话,好像没有什么影响…
因为要从u到v完全可以走之前的更短的路径而不是走直接相连的边…
如果比原来的距离大的话怎么办呢?
我们想想floyd算法,它是枚举每一个中间点,看看过这个点的路径能不能更新最短路…
也就是说,加了一条更短的边(u,v)以后,如果某两点间最短路径不经过边(u,v),那么它就不会受到影响。也就是说,只有经过点u和v的最短路径才可能受到影响。
那么我们就尝试用u和v作为中间点,尝试更新最短路!
问题好像迎刃而解了…
不存在的!
这样跑复杂度也会爆炸!
因为每一个刚刚建好的村庄可以和所有已经建好的村庄连线…而每个点都要求一遍最短路…
考虑优化,上面说到,只有经过并且经过v的最短路才会受到影响,所以我们可以用v作为中间点更新出u的到所有点的最短路,复杂度O(n),再用u作为中间点更新所有的最短路。
为什么是对的?
例如加边(u,v)后s–>t的最短路应更新为s–>…–>v–>u–>…–>t,如果用u作为中间点,我们就把最短路分成了两段,一段是s–>u,另一段是u–>t。u–t的最短路是不变的,上面的做法就是先更新s–>u的最短路(以v为中间点),这样就能求出s–>t的最短路了。
然后就过了!
(这个优化好像很弱)
代码如下:
#include<cstdio>#include<iostream>using namespace std;const int INF=1e9;int val[201][201];int dis[201][201];int ed[201][201]={0};int t[201];int ans[50001];int n,m;void dijkstra(int k){ for(int i=0;i<n;i++) { if(ed[i][k]&&t[i]<=t[k]&&dis[i][k]>val[i][k]) //如果这条边已经建好了并且边长大于两点间本来的距离,就更新最短路 { dis[i][k]=dis[k][i]=val[i][k]; for(int j=0;j<n;j++) { if(dis[j][i]+dis[i][k]<dis[j][k]) dis[j][k]=dis[k][j]=dis[j][i]+dis[i][k]; } } } for(int i=0;i<n;i++) //以k为中间点的floyd { for(int j=0;j<n;j++) { if(dis[i][j]>dis[i][k]+dis[k][j]) dis[i][j]=dis[i][k]+dis[k][j]; } }}int main(){ scanf("%d%d",&n,&m); for(int i=0;i<n;i++) { scanf("%d",&t[i]); } for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { dis[i][j]=INF; } } for(int i=1;i<=m;i++) { int x,y,w; scanf("%d%d%d",&x,&y,&w); val[x][y]=val[y][x]=w; ed[x][y]=ed[y][x]=1; } int q,u,v,w,s,p=0; scanf("%d",&q); for(int l=1;l<=q;l++) { scanf("%d%d%d",&u,&v,&s); while(t[p]<=s&&p<n) //如果这个村庄在这一天已经修好了 { dijkstra(p); p++; } if(dis[u][v]>1e8) ans[l]=-1; //这个特判有些玄学... else ans[l]=dis[u][v]; } for(int i=1;i<=q;i++) { printf("%d\n",ans[i]); } return 0;}
- 洛谷【P1119】 灾后重建
- [洛谷P1119]灾后重建
- 洛谷 P1119 灾后重建
- 洛谷 P1119 灾后重建
- 洛谷 P1119 灾后重建
- 洛谷 P1119 灾后重建
- 洛谷P1119 灾后重建
- 洛谷 P1119 灾后重建
- 灾后重建 洛谷p1119
- 洛谷P1119灾后重建
- 洛谷 [P1119] 灾后重建
- [P1119]灾后重建
- P1119 灾后重建
- 洛谷 P1119 灾后重建(Floyd)
- 【luogu P1119】灾后重建
- luogu 【p1119】灾后重建
- floyd——洛谷P1119 灾后重建
- 洛谷P1119 灾后重建(floyd+思维)
- Quartz动态配置表达的方法
- 日常生活小技巧 -- UART 回环测试
- C语言——求素数和
- VGG16预训练学习笔记
- 字节和字符的区别
- 洛谷 P1119 灾后重建
- vs2017 xamarin开发android时jar转dll出错 can't load class 解决方法
- Android-第三方框架-网络请求之okhttp
- 数据结构实验之栈二:一般算术表达式转换成后缀式
- 查看电脑的ip地址
- kotlin的一些学习和使用时遇到的问题
- Java设计模式之六大原则
- MySQL--操作简记(联结表,组合查询(UNION))
- STL 容器