算法提高 道路和航路 SPFA 算法

我简单的描述一下题目,题目中所说的有道路和航路:

1.公路是双向的,航路是单向的;

2.公路是正值,航路可正可负;

每一条公路i或者航路i表示成连接城镇Ai(1<=A_i<=T)和Bi(1<=Bi<=T)代价为Ci;每一条公路,Ci的范围为0<=Ci<=10,000;

由于奇怪的运营策略,每一条航路的Ci可能为负的,也就是-10,000<=Ci<=10,000。

数据规模与约定

对于20%的数据,T<=100,R<=500,P<=500;

对于30%的数据,R<=1000,R<=10000,P<=3000;

对于100%的数据,1<=T<=25000,1<=R<=50000,1<=P<=50000。

输入格式

输入的第一行包含四个用空格隔开的整数T,R,P,S。(表示共有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
讲解:如果数据量比较少的话,很多方法都能做啦,什么Dijkstra,Bellman-ford,Floyd,都能简单的解决了,但是要想得满分,这道题目的数据量太大了,我直接套用的spfa   的模板直接过了,模板不错的,还能保存路径的;
  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<vector>
  6 #include<queue>
  7 #include<stack>
  8 using namespace std;
  9 const int MAXN = 25100;
 10 const int INF=0x7FFFFFFF;
 11 struct edge
 12 {
 13     int to,weight;
 14 };
 15 int T,R,P,S;
 16 vector<edge>adjmap[MAXN];//邻接表
 17 bool in_queue[MAXN];//顶点是否在队列中
 18 int in_sum[MAXN];//顶点入队的次数
 19 int dist[MAXN];//源点到各点的最短路
 20 int path[MAXN];//存储到达i的前一个顶点
 21 int nodesum;  //顶点数
 22 int edgesum;  //边数
 23 bool spfa(int source)
 24 {
 25     deque< int > dq;
 26     int i,j,x,to;
 27     for(int i = 1;i<=T;i++)//初始化函数
 28     {
 29          in_sum[i]= 0;
 30          in_queue[i]=false;
 31          dist[i]=INF;
 32          path[i]=-1;
 33     }
 34     dq.push_back(source);
 35     in_sum[source]++;
 36     dist[source]=0;        //到达本身的最短距离为0
 37     in_queue[source]= true;
 38     while(!dq.empty())
 39     {
 40         x = dq.front();
 41         dq.pop_front();
 42         in_queue[x]=false;
 43         for(int i = 0;i<adjmap[x].size();i++)
 44         {
 45             to = adjmap[x][i].to;
 46             if((dist[x]<INF) && ( dist[to]>dist[x]+adjmap[x][i].weight) )
 47             {
 48                 dist[to] = dist[x]+adjmap[x][i].weight;
 49                 path[to] = x;
 50                 if(!in_queue[to])
 51                 {
 52                     in_queue[to] = true;
 53                     in_sum[to]++;
 54                     if(in_sum[to] == nodesum) return false;
 55                     if(!dq.empty())
 56                     {
 57                        if(dist[to]>dist[dq.front()])  dq.push_back(to);
 58                        else dq.push_front(to);
 59                     } else dq.push_back(to);
 60              }
 61          }
 62       }
 63     }
 64     return true;
 65 }
 66 void print_path(int x)
 67 {
 68     //输出最小的花费
 69     if(dist[x] == INF)//到不了的路径
 70         cout<<"NO PATH"<<endl;
 71     else cout<<dist[x]<<endl;
 72 
 73 //   下面是输出路径
 74 //    stack<int>s;
 75 //    int w = x;
 76 //    while(path[w]!=-1)
 77 //    {
 78 //        s.push(w);
 79 //        w=path[w];
 80 //    }
 81 //    //以下是经过的路径
 82 //    while(!s.empty())
 83 //    {
 84 //        cout<<s.top()<<" ";
 85 //        s.pop();
 86 //    }
 87 //    cout<<endl;
 88 }
 89 int main()
 90 {
 91 
 92     edge temp;
 93     int s,e,w;
 94     scanf("%d %d %d %d",&T,&R,&P,&S);
 95     for(int i = 1;i<T;i++)
 96         adjmap[i].clear();//清空邻接表
 97     for(int i = 1; i<=R; i++)
 98     {
 99         scanf("%d %d %d",&s,&e,&w);
100         temp.to = e;
101         temp.weight = w;
102         adjmap[s].push_back(temp);
103         temp.to = s;
104         adjmap[e].push_back(temp);//  公路的是双向的,需要放入两次
105     }
106     for(int i = 1;i<=P;i++)
107     {
108         scanf("%d %d %d",&s,&e,&w);
109         temp.to = e;
110         temp.weight = w;
111         adjmap[s].push_back(temp);
112     }
113     if(spfa(S))
114     {
115         for(int i =1;i<=T; i++ )
116              print_path(i);
117     }
118    // else cout<<"图中存在负权回路"<<endl;
119     return 0;
120 }
原文地址:https://www.cnblogs.com/lovychen/p/4409543.html