luogu 【p1119】灾后重建
来源:互联网 发布:js拖动滑块实现验证码 编辑:程序博客网 时间:2024/06/08 14:20
灾后重建
题目背景
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。
输入输出样例
输入样例#1:
4 5
1 2 3 4
0 2 1
2 3 1
3 1 2
2 1 4
0 3 5
4
2 0 2
0 1 2
0 1 3
0 1 4
输出样例#1:
-1
-1
5
4
说明
对于30%的数据,有N≤50;
对于30%的数据,有t[i] = 0,其中有20%的数据有t[i] = 0且N>50;
对于50%的数据,有Q≤100;
对于100%的数据,有N≤200,M≤N*(N-1)/2,Q≤50000,所有输入数据涉及整数均不超过100000。
这道题加深了我对Floyed算法的理解。
首先谈谈Floyed算法:Floyd算法的本质是动态规划,其转移方程为:f[k][i][j] = min( f[k-1][i][j], f([k-1][i][k])+f[k-1][k][j] )。
f[k][i][j]表示路径除开起点i与终点j,只经过前k个点中的某些点,从i到j的最小值。计算这个值只需要考虑两种情况:最短路经过k,和最短路不经过k(那么就经过前k-1个点中的某些点)。由于k要从k-1转移而来,自然k为最外层的循环。而经过滚动(类似于背包问题)后,就变成了我们熟悉的f[i][j]=min(f[i][j],f[i][k]+f[k][j])了。
思路一(30分,TLE七个点):
对于每一次询问,都把小于当钱时间的点和边加入到图中,然后每一次询问都跑一边Floyed,这样做肯定会超时啊
//如果输入数据没有将时间排序,需要先排序,这点很重要 //每次询问都跑Floyed肯定会超时 #include<cstdio>#include<cstring>using namespace std;bool b[201];//某村庄是否修好 int n,m,x,y,z,q,u,v,time,t[201],t1[201],f[201][201],matrix[201][201];//t1存不大于当前时间的点的编号,作为中转站,matrix只用来存原图 int main(){ memset(f,0x7f,sizeof(f)); memset(matrix,0x7f,sizeof(matrix)); scanf("%d%d",&n,&m); for (int i=0; i<n; i++)//注意从0开始 scanf("%d",&t[i]); for (int i=1; i<=m; i++) { scanf("%d%d%d",&x,&y,&z); matrix[x][y]=matrix[y][x]=z; } scanf("%d",&q); for (int l=1; l<=q; l++) { int num=0; scanf("%d%d%d",&u,&v,&time); for (int i=0; i<n; i++) if (t[i]<=time){ t1[++num]=i; b[i]=true; }//找到在当前时间之内可以修好的村庄,可以作为中转站 for (int i=0; i<n; i++)//如果两个村庄都修建好了,就把它们之间的最短距离初始化为两点间的距离 for(int j=0; j<n; j++) if (b[i]&&b[j]) f[i][j]=f[j][i]=matrix[i][j]; for (int k=1; k<=num; k++) { for (int i=0; i<n; i++) for (int j=0; j<n; j++) { if (f[i][j]>f[i][t1[k]]+f[t1[k]][j]&&i!=j&&i!=t1[k]&&t1[k]!=j&&f[i][t1[k]]<0x7f7f7f7f&&f[t1[k]][j]<0x7f7f7f7f)//需要加那些限制条件? f[i][j]=f[i][t1[k]]+f[t1[k]][j]; } } if (f[u][v]==0x7f7f7f7f) printf("-1\n"); else printf("%d\n",f[u][v]); } return 0;}
思路二(100分):改变思路:看中转点k每一次自增能解决什么问题,能回答问题就输出。还要开一个bool数组b[201],标记某村庄是否已经作为中转点,可以从n^3q的复杂度变为 n^3+q的复杂度,这样还是可以接受的。
代码如下:
//改变思路:看k每一次自增能解决什么问题 //所以要将提出的问题存到一个数组里 #include<cstdio>#include<cstring>using namespace std;bool b[201];int n,m,x,y,z,q,t[201],f[201][201];int from[50001],to[50001],day[50001];//questions;int main(){ memset(f,0x7f,sizeof(f)); scanf("%d%d",&n,&m); for (int i=0; i<n; i++) f[i][i]=0;//初始化 for (int i=0; i<n; i++)//注意从0开始 scanf("%d",&t[i]); for (int i=1; i<=m; i++) { scanf("%d%d%d",&x,&y,&z); f[x][y]=f[y][x]=z; } scanf("%d",&q); int tot=0; for (int i=1; i<=q; i++) { scanf("%d%d%d",&from[i],&to[i],&day[i]); } for (int l=1; l<=q; l++) { for (int k=0; k<n; k++) if (t[k]<=day[l]&&!b[k]) { b[k]=1; for (int i=0; i<n; i++) for (int j=0; j<n; j++) if (f[i][j]>f[i][k]+f[k][j]&&i!=j&&i!=k&&k!=j&&f[i][k]<0x7f7f7f7f&&f[k][j]<0x7f7f7f7f) f[i][j]=f[i][k]+f[k][j]; } if (t[from[l]]<=day[l]&&t[to[l]]<=day[l]&&f[from[l]][to[l]]!=0x7f7f7f7f) printf("%d\n",f[from[l]][to[l]]); else printf("-1\n"); } return 0;}
所以说编程也是美的。代码以境界为最上,有境界则自成高格,自有名句。宽嫂之代码所以独绝者在此:http://blog.csdn.net/Cansult/article/details/77628415
- 【luogu P1119】灾后重建
- luogu 【p1119】灾后重建
- luogu解题报告:P1119灾后重建【图论/最短路】
- [P1119]灾后重建
- P1119 灾后重建
- 洛谷【P1119】 灾后重建
- [洛谷P1119]灾后重建
- 洛谷 P1119 灾后重建
- 洛谷 P1119 灾后重建
- 洛谷 P1119 灾后重建
- 洛谷 P1119 灾后重建
- 洛谷P1119 灾后重建
- 洛谷 P1119 灾后重建
- 灾后重建 洛谷p1119
- 洛谷P1119灾后重建
- 洛谷 [P1119] 灾后重建
- P1119 灾后重建(离线Floyed)
- 洛谷 P1119 灾后重建(Floyd)
- 聊聊ES7与ES8特性
- 3d data set
- 一些问题解答
- java提高篇(十三)-----equals()方法总结
- Boolean类型
- luogu 【p1119】灾后重建
- 获得执行计划
- 使用ssh公钥实现免密码登录
- Redis 数据操作
- RecyclerView GridLayoutManager实现复杂的列数变化的布局
- 虚拟机磁盘丢失的数据恢复过程
- HTTP 请求帮助类和日志帮助类
- FFmpeg学习—android 利用ffmpeg 集成libfdk-aac 录制aac 音频文件
- 链接转载