题目链接: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
#include
#include
#include
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;
queueq;
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};
queueq;
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);
}
}