zoukankan      html  css  js  c++  java
  • HDU 2680 有点坑的稠密图最短路(dij各版本)

    Choose the best route

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 14431    Accepted Submission(s): 4711


    Problem Description
    One day , Kiki wants to visit one of her friends. As she is liable to carsickness , she wants to arrive at her friend’s home as soon as possible . Now give you a map of the city’s traffic route, and the stations which are near Kiki’s home so that she can take. You may suppose Kiki can change the bus at any station. Please find out the least time Kiki needs to spend. To make it easy, if the city have n bus stations ,the stations will been expressed as an integer 1,2,3…n.
     

    Input
    There are several test cases. 
    Each case begins with three integers n, m and s,(n<1000,m<20000,1=<s<=n) n stands for the number of bus stations in this city and m stands for the number of directed ways between bus stations .(Maybe there are several ways between two bus stations .) s stands for the bus station that near Kiki’s friend’s home.
    Then follow m lines ,each line contains three integers p , q , t (0<t<=1000). means from station p to station q there is a way and it will costs t minutes .
    Then a line with an integer w(0<w<n), means the number of stations Kiki can take at the beginning. Then follows w integers stands for these stations.
     

    Output
    The output contains one line for each data set : the least time Kiki needs to spend ,if it’s impossible to find such a route ,just output “-1”.
     

    Sample Input
    5 8 5 1 2 2 1 5 3 1 3 4 2 4 7 2 5 6 2 3 5 3 5 1 4 5 1 2 2 3 4 3 4 1 2 3 1 3 4 2 3 2 1 1
     

    Sample Output
    1 -1
     

    Author
    dandelion
     

    Source

    这道题比较任性,一看还是比较裸的dij最短路,但是不知道几点坑处,经验不足,就会像我这样多贡献几发TLE。


    一开始上dij+队列优化,第一次超时,想到以前遇到一个变形最短路题矩阵存图就会T,然后换用邻接表存,orz,不够熟练,调试了好几回,终于测试数据通过提交,还是T。

    这下就开始懵了,上网看了别人代码,啊,普通的dij都能过啊。突然想到scanf输入超时问题。改了,加过滤路线,A,果然。。。


    坑点:这题后台的数据是按照稠密图给的,而且有大量的重合路线数据,必须特判,取最小,不然肯定得不出最短路。

               邻接表存稠密图肯定会炸,而且邻接表是以边为编号,不好读取点的坐标,所以也不好过滤路线。所这题只能用矩阵存图。当然SPFA也可以了。。

    这题让我温习了各种版本的dij写法。。。也了解了我这里的邻接表是反向插,如果用vector存的话是正向插,更好理解。话说堆优化的dij还没敲过。。


    AC普通版:

    #include <bits/stdc++.h>
    
    typedef long long ll;
    using namespace std;
    const int maxn = 1000+5;
    int mp[maxn][maxn];
    int vis[maxn];
    int dis[maxn];
    const int inf = 0x3f3f3f3f;
    int main()
    {
    //    freopen("in.txt","r",stdin);
        int n,m,e;
        while(~scanf("%d%d%d",&n,&m,&e))
        {
            for(int i = 1; i <= n; i++)
            {
                dis[i] = inf;
            }
            dis[0] = 0;
    
            for(int i = 0; i <= n; i++)
            {
                for(int j = 0; j <= n; j++)
                {
                    if(i==j) mp[i][j] = 0;
                        else mp[i][j] = inf;
                }
            }
            while(m--)
            {
                int a,b,c;
    //            cin>>a>>b>>c;
                scanf("%d%d%d",&a,&b,&c);
    //            mp[a][b] = c;
                //原文中说两城市之间不只一条路,直接读会出错,比如后出现mp[1][2] = 100会覆盖之前的mp[1][2] = 3,肯定不是最短路
                if(c<mp[a][b])
                    mp[a][b] = c;
            }
                int w;
                cin>>w;
                while(w--) {
                    int t;
                    scanf("%d",&t);
                    mp[0][t] = 0;
                }
            for(int i = 0; i <= n; i++)
            {
                dis[i] = mp[0][i];
                vis[i] = 0;
            }
            vis[0] = 1;
            ;
            int u;
            for(int i = 0; i <= n; i++)
            {
                int Min = inf;
                for(int j = 0; j <= n; j++)
                {
                    if(dis[j]<Min&&!vis[j]) {
                        u=j;
                        Min = dis[j];
                    }
                }
                vis[u] = 1;
                for(int d = 0; d <= n; d++) {
                    if(dis[u]+mp[u][d] < dis[d]&&!vis[d])
                        dis[d] = dis[u]+mp[u][d];
                }
            }
            if(dis[e] == inf)
                printf("-1
    ");
            else
                printf("%d
    ",dis[e]);
        }
        return 0;
    }
    


    AC:dij+队列优化矩阵存图:

    #include <bits/stdc++.h>
    
    typedef long long ll;
    using namespace std;
    const int maxn = 1000+5;
    const int INF = 0x3f3f3f3f;
    ll ans;
    int mp[maxn][maxn];
    int dis[maxn];
    struct Node {
        int num;
        int val;
        }node;
    
    priority_queue<Node> q;
    
    bool operator < (Node a,Node b) {
        return a.val > b.val;
    }
    
    int main() {
    //    freopen("in.txt","r",stdin);
        int n,m,e;
        while(~scanf("%d%d%d",&n,&m,&e)) {
    //        memset(mp,-1,sizeof(mp));
            for(int i = 0; i<=n; i++)
                for(int j = 0; j<=n; j++)
                    mp[i][j] = INF;
            while(!q.empty()) q.pop();
    
            for(int i = 0; i < m; i++) {
                int a,b,c;
                scanf("%d%d%d",&a,&b,&c);
                if(c<mp[a][b])
                    mp[a][b] = c;
            }
                int w;
                cin>>w;
                while(w--) {
                    int t;
                    scanf("%d",&t);
                    mp[0][t] = 0;
                }
    
                for(int i = 1; i <= n; i++) {
                    dis[i] = INF;
                }
    
                dis[0] = 0;
                node.num = 0;
                node.val = 0;
                q.push(node);
                while(!q.empty()) {
                    for(int i = 1; i <= n; i++) {
                        if(mp[q.top().num][i] != INF&&dis[i] > dis[q.top().num]+mp[q.top().num][i]) {
                            dis[i] = dis[q.top().num] + mp[q.top().num][i];
                            node.num = i;
                            node.val = dis[i];
                            q.push(node);
                        }
                    }
                    q.pop();
            }
    
            if(dis[e]!=INF)
              cout<<dis[e]<<endl;
              else
                puts("-1");
            }
        }
    

    TLE队列邻接表版:

    #include <cstdio>
    #include <cmath>
    #include <cctype>
    #include <algorithm>
    #include <cstring>
    #include <utility>
    #include <string>
    #include <iostream>
    #include <map>
    #include <set>
    #include <vector>
    #include <queue>
    #include <stack>
    
    
    typedef long long ll;
    using namespace std;
    const int maxn = 2000+10;
    const int INF = 0x3f3f3f3f;
    //int mp[maxn][maxn];
    int first[maxn];
    int num,dis[1010];
    
    struct Node {
        int id;
        int val;
        }node;
    
    struct Edge {
        int id;//以此点为出边找边
        int val;
        int next;
        }e[maxn];
    
    void add(int u,int v,int d) {
        //num边的编号
        e[num].id  = v;
        e[num].val = d;
        e[num].next = first[u];
        first[u] = num;
        num++;
    }
    
    priority_queue<Node> q;
    
    bool operator < (Node a,Node b) {
        return a.val > b.val;
    }
    
    int main() {
    //    freopen("in.txt","r",stdin);
        int n,m,End;
        while(~scanf("%d%d%d",&n,&m,&End)) {
            memset(first,-1,sizeof(first));
            while(!q.empty()) q.pop();
    
            for(int i = 0; i < m; i++) {
                int a,b,c;
                scanf("%d%d%d",&a,&b,&c);
                add(a,b,c);
            }
                int w;
                scanf("%d",&w);
                while(w--) {
                    int t;
                    scanf("%d",&t);
                    add(0,t,0);
                }
    
                for(int i = 1; i <= n; i++) {
                    dis[i] = INF;
                }
                Node cur;
                dis[0] = 0;
                node.id = 0;
                node.val = 0;
                q.push(node);
                while(!q.empty()) {
                    if(cur.id == End){
                        break;
                }
                    cur = q.top();
                    q.pop();
                    //i为边的编号
                    for(int i = first[cur.id]; i != -1; i = e[i].next) {
                        if(dis[e[i].id] > e[i].val+cur.val) {
                            dis[e[i].id] = e[i].val+cur.val;
                            node.id = e[i].id;
                            node.val = dis[e[i].id];
                            q.push(node);
                        }
                    }
            }
    //        for(int i = 0; i <= n; i++) {
    //            printf("初始点到%d点的距离为%d
    ",i,dis[i]);
    //        }
            if(dis[End]!=INF)
              cout<<dis[End]<<endl;
              else
                puts("-1");
            }
        }
    


    普通的dij时间复杂度是找点+找边为O(N^2),队列优化可以把找点时间降到log n,加邻接表就是(m+n)log n,当m远小于n^2的时候,要比n^2小的多,但是如果是稠密图,m比较大的时候,(m+n)log n就比n^2还要大了。


    附上队列优化邻接表正向插入的vector实现dij算法,真是好理解一些

    /*
    Dijkstra的算法思想:
    在所有没有访问过的结点中选出dis(s,x)值最小的x
    对从x出发的所有边(x,y),更新
    dis(s,y)=min(dis(s,y),dis(s,x)+dis(x,y))
    */
    #include <iostream>
    #include <cstdio>
    #include <queue>
    #include <vector>
    using namespace std;
    const int Ni = 10000;
    const int INF = 1<<27;
    struct node{
        int x,d;
        node(){}
        node(int a,int b){x=a;d=b;}
        bool operator < (const node & a) const
        {
            if(d==a.d) return x<a.x;
            else return d > a.d;
        }
    };
    vector<node> eg[Ni];
    int dis[Ni],n;
    void Dijkstra(int s)
    {
        int i;
        for(i=0;i<=n;i++) dis[i]=INF;
        dis[s]=0;
        //用优先队列优化
        priority_queue<node> q;
        q.push(node(s,dis[s]));
        while(!q.empty())
        {
            node x=q.top();q.pop();
            for(i=0;i<eg[x.x].size();i++)
            {
                node y=eg[x.x][i];
                if(dis[y.x]>x.d+y.d)
                {
                    dis[y.x]=x.d+y.d;
                    q.push(node(y.x,dis[y.x]));
                }
            }
        }
    }
    int main()
    {
        int a,b,d,m;
        while(scanf("%d%d",&n,&m),n+m)
        {
            for(int i=0;i<=n;i++) eg[i].clear();
            while(m--)
            {
                scanf("%d%d%d",&a,&b,&d);
                eg[a].push_back(node(b,d));
                eg[b].push_back(node(a,d));
            }
            Dijkstra(1);
            printf("%d
    ",dis[n]);
        }
        return 0;
    }
    /*
    6 6
    1 2 2
    3 2 4
    1 4 5
    2 5 2
    3 6 3
    5 6 3
    */



  • 相关阅读:
    微信开放平台扫码登录回调后 state 参数丢失遗漏的解决方案
    WPF 图片源为空时展示默认图片
    使用批处理(.bat)文件一键编译 .NET CORE 网站并发布至 IIS
    10倍程序员的思考模型
    以TiDB热点问题来谈Region的调度流程
    Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel的解决办法(react Hooks)
    react+tsx+antd表格点击行触发单选复选事件(类型xx上不存在属性xx的解决办法)
    does not exist on type 'JSX.IntrinsicElements'.does not exist on type 'JSX.IntrinsicElements'.的解决办法
    antd-react自定义显示表格操作按钮
    react+tsx+antd关于表单二次弹框
  • 原文地址:https://www.cnblogs.com/zhangmingzhao/p/7256613.html
Copyright © 2011-2022 走看看