【蓝桥杯】试题 算法训练 最短路&道路和航路

问题描述

资源限制
  时间限制:1.0s 内存限制:256.0MB
问题描述
  给定一个n个顶点,m条边的有向图(其中某些边权可能为负,但保证没有负环)。请你计算从1号点到其他点的最短路(顶点从1到n编号)。

输入格式  
  第一行两个整数n, m。
接下来的m行,每行有三个整数u, v, l,表示u到v有一条长度为l的边。
输出格式
  共n-1行,第i行表示1号点到i+1号点的最短路。

输入样例

3 3
1 2 -1
2 3 -1
3 1 2

输出样例

-1
-2

解题思路

不断循环可走路径,计算从s到任意一点的最短距离。当某次循环中没有更新最短路径,说明此时已经达到最佳效果。同样当循环次数达到顶点数(n)时,说明存在负圈。参考链接

解题代码

#include<iostream>
#include<cstring>
#define INF 0x3f3f3f3f
using namespace std;
int n,m;
struct node
{
     int from,to,cost;
};
node edge[200010];
//表示点N到i点的最短距离 
int d[20005];
//如果存在最短路径,返回true,否则为存在负圈
bool shortway(int s)
{
     memset(d,INF,sizeof(d));
     d[s]=0;
     int j=0;
     while(true)
     {
          bool update=false; 
          for(int i=0;i<m;i++)
         {
              node ee=edge[i];
              //当这条边的起点在路线中,并且走这条路更短一些时 
              if(d[ee.from]!=INF&&d[ee.to]>d[ee.from]+ee.cost)
              {
                   d[ee.to]=d[ee.from]+ee.cost;
                   update=true;
              }
         }
         j++;
         //不再更新,说明已经全部为最短路 
         if(!update) return true;
         //当循环次数等于顶点数时,说明有负圈 
         if(j==n) return false;
     }  
}
int main()
{
     //n个顶点,m条边
     cin>>n>>m;
     int u,v,l;
     //可走路线存入edge,当是双向路线时,存入两次
     for(int i=0;i<m;i++)
     {
          cin>>u>>v>>l;
          edge[i].from=u-1;
          edge[i].to=v-1;
          edge[i].cost=l;
          //edge[i+m].from=u-1;
          //edge[i+m].to=v-1;
          //edge[i+m].cost=l;
     }
     if(shortway(0))
     {
          for(int i=1;i<n;i++)
             cout<<d[i]<<endl;
     }
     return 0;
} 

最短路模板应用(试题 算法提高 道路和航路):

问题描述

资源限制
  时间限制:1.0s 内存限制:256.0MB
问题描述
  农夫约翰正在针对一个新区域的牛奶配送合同进行研究。他打算分发牛奶到T个城镇(标号为1…T),这些城镇通过R条标号为(1…R)的道路和P条标号为(1…P)的航路相连。
  每一条公路i或者航路i表示成连接城镇Ai(1<=A_i<=T)和Bi(1<=Bi<=T)代价为Ci。每一条公路,Ci的范围为0<=Ci<=10,000;由于奇怪的运营策略,每一条航路的Ci可能为负的,也就是-10,000<=Ci<=10,000。
  每一条公路都是双向的,正向和反向的花费是一样的,都是非负的。
  每一条航路都根据输入的Ai和Bi进行从Ai->Bi的单向通行。实际上,如果现在有一条航路是从Ai到Bi的话,那么意味着肯定没有通行方案从Bi回到Ai。
  农夫约翰想把他那优良的牛奶从配送中心送到各个城镇,当然希望代价越小越好,你可以帮助他嘛?配送中心位于城镇S中(1<=S<=T)。
 
输入格式  
  输入的第一行包含四个用空格隔开的整数T,R,P,S。
  接下来R行,描述公路信息,每行包含三个整数,分别表示Ai,Bi和Ci。
  接下来P行,描述航路信息,每行包含三个整数,分别表示Ai,Bi和Ci。
输出格式
  输出T行,分别表示从城镇S到每个城市的最小花费,如果到不了的话输出NO PATH。

输入样例

6 3 3 4
1 2 5
3 4 5
5 6 10
3 5 -100
4 6 -100
1 3 -10

输出样例

NO PATH
NO PATH
5
0
-95
-100

解题思路

简化题目:有t个顶点,有r条双向路径,p条单向路径,即共有2*r+p条路径。求顶点s到各顶点的最短路径。
解题结果:有两个测试点超时,得分90。

解题代码

#include<iostream>
#include<cstring>
#define INF 0x3f3f3f3f
using namespace std;
//t个城镇,r条公路,p条航道,中心在s
//公路双向,航道单向 
int t,r,p,s;
struct edge
{
     int from,to,cost;
 } ;
 edge ee[150010];
 //从中心s出发到各城镇的最短路 
 int d[25010]; 
 bool shortway(int s)
 {
      memset(d,INF,sizeof(d));
      d[s]=0;
      int j=0;
      while(true)
      {
           bool update=false;
           for(int i=0;i<2*r+p;i++)
           {
                edge temp=ee[i];
                if(d[temp.from]!=INF&&d[temp.to]>d[temp.from]+temp.cost)
                {
                     d[temp.to]=d[temp.from]+temp.cost;
                     update=true;
                }
           } 
           j++;
           if(!update) return true;
           if(j==t)  return false;
     }  
 } 
int main()
{
     cin>>t>>r>>p>>s;
     int ai,bi,ci;
     for(int i=0;i<r;i++)
     {
          cin>>ai>>bi>>ci;
          ee[i].from=ai-1;
          ee[i].to=bi-1;
          ee[i].cost=ci;
          ee[i+r].from=bi-1;
          ee[i+r].to=ai-1;
          ee[i+r].cost=ci;
     } 
      for(int i=0;i<p;i++)
     {
          cin>>ai>>bi>>ci;
          ee[2*r+i].from=ai-1;
          ee[2*r+i].to=bi-1;
          ee[2*r+i].cost=ci;   
      }
     if(shortway(s-1)) cout<<"Y"<<endl;
     for(int i=0;i<t;i++)
     {
          if(d[i]!=INF) cout<<d[i]<<endl;
          else cout<<"NO PATH"<<endl;
     }
     return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值