[SPFA+路径输出] ZOJ3088 Easter Holidays

来源:互联网 发布:淘宝卖的好的飞机杯 编辑:程序博客网 时间:2024/04/30 12:16

题目链接: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>


0 0
原创粉丝点击