题目链接:Easter Holidays
题意:n个点m+k条边,任意s,e两点通过m边集的最大距离为MAX,通过k边集的最小距离是MIN,要求MAX比上MIN的最大值,还要输出从k中e到s,从m中s到e的路径。
做这题的时候真是心中万只草泥马奔腾。
要求任意点的最短路最长路,一般来说用Floyd(O(n^3)),然而这题范围用N^3复杂度高达10^9,显然不行。
但是注意到边数只有10^3,用SPFA的O(e)足够了,枚举N求出任意两点最大值最小值,复杂度O(n*e),10^6,1sec足够。
然而求最大值和最小值需要写两遍SPFA,虽然可以用if写在一起,但是分开写更直白一些,复制一遍,不用为难自己。
打算复习一下几个最短路算法,于是又回过头看了看以前写的代码,突然想起vector做邻接表的效率似乎很慢,于是又学习了用数组模拟邻接表的方法,而且也很简单,效率也快不少,温故而知新啊,我记得以前好像也看过这种方法,然而那时好像看不懂啊。说不定再手写queue可以更快?
代码在OJ跑20ms,这么快是数据太水了么,难道用Floyd可以水过?
#include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; int n, m, k; int u[2005], v[2005], w[2005]; int fir[2005], nex[2005], cnt; int path[1005][1005], path1[1005][1005]; int dis[1005][1005], dis1[1005][1005]; void add(int a, int b, int c){ u[cnt] = a, v[cnt] = b, w[cnt] = c; nex[cnt] = fir[u[cnt]]; fir[u[cnt]] = cnt ++; } void spfamax(int s){ //最长路 bool vis[1005]={0}; for(int i = 0; i <= n; ++i) dis[s][i] = 0; queue<int>q; q.push(s); vis[s] = 1; dis[s][s] = 0; while( !q.empty() ){ int a = q.front(); q.pop(); vis[a] = 0; int k = fir[a]; while(k != -1){ int b = v[k], c = w[k]; if(dis[s][b] < dis[s][a] + c){ dis[s][b] = dis[s][a] + c; path[s][b] = a; if(!vis[b]){ vis[b] = 1; q.push(b); } } k = nex[k]; } } } void spfamin(int s){ //最短路 bool vis[1005]={0}; queue<int>q; for(int i = 0; i <= n; ++i) dis1[s][i] = 0xfffffff; q.push(s); vis[s] = 1; dis1[s][s] = 0; while( !q.empty() ){ int a = q.front(); q.pop(); vis[a] = 0; int k = fir[a]; while(k != -1){ int b = v[k], c = w[k]; if(dis1[s][b] > dis1[s][a] + c){ dis1[s][b] = dis1[s][a] + c; path1[s][b] = a; if(!vis[b]){ vis[b] = 1; q.push(b); } } k = nex[k]; } } } void print(int path[], int e,int flag){ if(flag) { if(path[e] == -1) return; } //避免s结点输出两次 else { if(e == -1) return;} print(path, path[e],flag); printf("%d ",e); } int main(){ int T,a,b,c; scanf("%d", &T); while( T-- ){ memset(path, -1, sizeof(path)); memset(path1, -1, sizeof(path1)); scanf("%d %d %d", &n, &m, &k); cnt = 1; memset(fir, -1, sizeof(fir)); for(int i = 1; i <= m; ++i){ scanf("%d%d%d",&a, &b, &c); add(a, b, c); } for(int i = 1; i <= n; ++i) spfamax(i); cnt = 1; memset(fir, -1, sizeof(fir)); for(int i = 1; i <= k; ++i){ scanf("%d%d%d",&a, &b, &c); add(a, b, c); } for(int i = 1; i <= n; ++i) spfamin(i); double t=0; int s=0,e=0; for (int i = 1; i <= n; ++i){ //枚举s和e for (int j = 1; j <= n; ++j){ if(i == j || dis[i][j] == 0 || dis1[j][i] == 0xfffffff) continue; if(dis[i][j]*1.0 / dis1[j][i] > t) t = dis[i][j]*1.0 / dis1[j][i], s = i, e = j; } } print(path1[e], s, 0); print(path[s], e, 1); printf("\n%.3f\n",t); } }<strong> </strong>