华师一附中OI组

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 1491|回复: 2
打印 上一主题 下一主题

最短路径 讨论

[复制链接]

738

主题

1485

帖子

5422

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
5422
跳转到指定楼层
楼主
发表于 2018-4-14 20:39:24 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
给出一个有向图,请输出从某一点出发到所有点的最短路径长度。
输入第一行包含三个整数N、M、S,分别表示点的个数、有向边的个数、出发点的编号。接下来M行每行包含三个整数Fi、Gi、Wi,分别表示第i条有向边的出发点、目标点和长度。输出一行,包含N个用空格分隔的整数,其中第i个整数表示从点S出发到点i的最短路径长度(若S=i则最短路径长度为0,若从点S无法到达点i,则最短路径长度为2147483647)
【思路】典型的做法是dijistra,这个我们用邻接表来存图,邻接矩阵虽然直观确实太占空间了。
  1. #include<iostream>
  2. using namespace std;
  3. const int inf=2147483647;
  4. const int mm=500050;
  5. const int mn=10010;
  6. int n,m,s;
  7. int nxt[mm],ev[mm],ew[mm];
  8. int dist[mn],vist[mn],nbs[mn],p[mn];

  9. int getmin()
  10. {
  11.     int m,k,i;
  12.     m=inf;
  13.     k=0;  ///起点,无路可找的时候就返回0
  14.     ///for (i=1;i<=n;i++)  cout<<dist[i]<<' '; cout<<endl;
  15.     for (i=1; i<=n; i++)
  16.         if (!vist[i])
  17.             if (dist[i]<m)
  18.             {
  19.                 m=dist[i];
  20.                 k=i;
  21.             }
  22.     return k;
  23. }

  24. void dijkstra(int src)
  25. {
  26.     int i,j,u,v;
  27.     for(i=1; i<=n; i++)
  28.     {
  29.         dist[i]=inf;
  30.         vist[i]=0;
  31.     };
  32.     dist[src]=0;
  33.     while(1)  ///因为是找所有的路,所以这个和标准写法有点不一样
  34.     {
  35.         u=getmin();
  36.         if (u==0) return ;  ///靠这句话终结程序
  37.         vist[u]=1;
  38.         for(j=nbs[u]; j!=0; j=nxt[j])
  39.         {
  40.             v=ev[j];
  41.             if(!vist[v]&&dist[u]+ew[j]<dist[v])
  42.             {
  43.                 dist[v]=dist[u]+ew[j];
  44.                 p[v]=u;
  45.             }
  46.         }
  47.     }
  48. }
  49. void printpath(int i)///反推路径找到S到I的路
  50. {
  51.     int path[mn]={i,}; ///初始终点
  52.     int j=0,k=i;
  53.     while (p[k]!=0)  ///完全类似导弹飞机的倒推
  54.     {
  55.         j++;
  56.         path[j]=p[k];
  57.         k=p[k];
  58.     }
  59.     cout<<s<<"-->"<<i<<':';
  60.     for (; j>=0; j--) cout<<path[j];
  61.     cout<<endl;
  62. }
  63. int main()
  64. {
  65.     int i,u,v,w;
  66.     cin>>n>>m>>s;
  67.     for(i=1; i<=n; i++)nbs[i]=0;
  68.     for(i=1; i<=m; i++)
  69.     {
  70.         cin>>u>>v>>w;
  71.         nxt[i]=nbs[u];
  72.         nbs[u]=i;
  73.         ev[i]=v;
  74.         ew[i]=w;///这里考虑一下如何去掉重复的边,
  75.     }
  76.     dijkstra(s);
  77.     for (i=1; i<=n; i++)  cout<<dist[i]<<' ';
  78.     ///cout<<endl;
  79.     ///for (i=1; i<=n; i++)  printpath(i);
  80.     return 0;
  81. }

复制代码



回复

使用道具 举报

738

主题

1485

帖子

5422

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
5422
沙发
 楼主| 发表于 2018-4-14 20:39:45 | 只看该作者
这个程序对于一般的数据基本可以得到正确解,但是每次getmin确实会浪费不少的时间,快捷的做法我们就是用一个优先队列来存放dist[1..n],不要getmin函数,每次进循环的时候 u=pq.top();pq.pop(); 每次改了dist[v]后加上pq.push(v);当然,前面不要忘记:
struct cmp
{
    bool operator()(int &a, int &b) const
    {
        //因为优先出列判定为!cmp,所以反向定义实现最小值优先
        return dist[a] > dist[b];
    }
};

priority_queue<int, vector<int>, cmp> pq;  ///定义优先队列  注意比较方式
回复 支持 反对

使用道具 举报

738

主题

1485

帖子

5422

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
5422
板凳
 楼主| 发表于 2018-4-15 21:12:51 | 只看该作者
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|服务支持:DZ动力|华师一附中OI组  

GMT+8, 2024-12-25 14:44 , Processed in 0.153969 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表