题目:在小米之城,有 n个小镇(从 1 开始编号),这些小镇通过 m条双向火车铁轨相连,当然某些小镇之间也有公路相连。为了保证每两个小镇之间的人可以方便地互访,市长米小兔就在那些没有铁轨连接的小镇间建造了公路。在两个直接通过公路或铁路相连的小镇之间移动,需要花费 1 小时。火车只能走铁路,汽车只能走公路。
现在有一辆火车和一辆汽车同时从小镇 1 出发,各自前往小镇 n。但是,他们中途不能同时停在同一个小镇(但是可以同时停在小镇 n)。
现在请你来为火车和汽车分别设计一条线路,使火车和汽车尽可能快地到达小镇 n(即要求他们中最后到达小镇 n的时间最短)。
所有的公路或铁路可以被多次使用,求当火车、汽车中各自到达小镇时间最短时,总用时最小的一个。(火车和汽车可以同时到达小镇 n,也可以先后到达。)
这个题目我读了半个小时也没有读懂…(自我嫌弃.jpg)
输入:单组测试数据。
首先有 2 个整数 n和 m(2≤ n≤400,0≤m≤n*(n-1)/2)分别表示小镇的数目和铁轨的数目;
接下来的 m对数字,每对由两个整数 u 和 v 构成,表示小镇 u 和小镇 v之间有一条铁路。(1≤u,v≤n,u!=v)。
输入中保证两个小镇之间最多有一条铁路直接相连。
输出:输出一个整数,表示答案,如果没有合法的路线规划,输出 -1.
代码如下:
#include <bits/stdc++.h> #define inf 0x3f3f3f3f //十六进制无穷大 using namespace std; const int maxn=450; int mp[maxn][maxn]; //存图的二维数组定义在外部 int vis[maxn]; int dis[maxn]; int ans,sum,n,m; void dij(int v) { int _min,pos=-1; memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++) { dis[i]=mp[v][i]; } dis[v]=0; vis[v]=1; for(int i=1;i<n;i++) { _min=inf; //让最小值等于无穷小就可以当最小值比别的值大的时候进行替换 for(int j=1;j<=n;j++) { if(!vis[j]&&dis[j]<_min) //判断:vis那个值非零,并且dis那个值小于最小值 { _min=dis[j]; pos=j; } } vis[pos]=1; for(int j=1;j<=n;j++) { if(!vis[j]&&dis[j]>dis[pos]+mp[pos][j]) { dis[j]=dis[pos]+mp[pos][j]; } } } } int main() { scanf("%d%d",&n,&m); ans=sum=0; if(m==0) { printf("-1\n"); return 0; } else { memset(mp,inf,sizeof(mp)); memset(dis,inf,sizeof(dis)); for(int i=0;i<m;i++) { int u,v; scanf("%d%d",&u,&v); mp[u][v]=mp[v][u]=1; } dij(1); ans=dis[n]; if(ans==inf||m==(n*(n-1))/2) { printf("-1\n"); return 0; } else { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(mp[i][j]==1) { mp[i][j]=inf; } else { mp[i][j]=1; } } } dij(1); sum=dis[n]; } printf("%d\n",max(sum,ans)); } return 0; }
总结的来说,做最短路的题要注意这个方面:
1.尽量把初始化语句和算法语句封装成函数;
2.图的顶点和边的个数,以及存图的二维数组,定义在main函数外部;
3.注意是有向图还是无向图;
4.图的点是从1开始计算还是0开始计算;
5.每个测试样例一定要初始化存图的数组。
6.判断最短路存在与否的条件是arr[i][j] 是否等于INF。
Floyd的核心算法:
void floyd() { for(int k = 0 ; k < N ; k++) for(int i = 0 ; i < N ; i++) for(int j = 0 ; j < N ; j++) { if(arr[i][k] < INF && arr[k][j] < INF && arr[i][j] > arr[i][k] + arr[k][j]) arr[i][j] = arr[i][k] + arr[k][j]; } }