试题 算法提高 道路和航路
提交此题 评测记录
资源限制
时间限制: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
数据规模与约定
对于20%的数据,T<=100,R<=500,P<=500;
对于30%的数据,R<=1000,R<=10000,P<=3000;
对于100%的数据,1<=T<=25000,1<=R<=50000,1<=P<=50000。
解题思路:为了解有负边的最短路径问题(之前所学的Dijkstra 和Floyd 算法 都被免疫了。。。),我特地搜好多算法慕课,终于找到了Bellman_Ford算法(这个算法挺好理解的,就是不断的松弛操作),跑了一下,35分,后面的测试数据运行超时了。看了大佬们的解题思路,要用SPFA算法。等我学了SPFA,再来改进改进。。。未完待续。。。
二更:在B站上学了一波SPFA,立马把代码改了一遍,SPFA,就是BFS的时候加入松弛操作,利用了BFS求最优解的优点。改进后的代码,跑了85分,提升还是很大滴。。。
Bellman_Ford算法代码如下:
#include <iostream>
#include <vector>
using namespace std;
#define INF 65535
struct Way{
int u;
int v;
int w;
Way(){ }
Way(int uu,int vv,int ww):u(uu),v(vv),w(ww){ }
};
int T,R,P,S;
int dist[25010];
vector<Way> E;
void ReadInput(){
cin>>T>>R>>P>>S;
int A,B,C;
for(int i=0;i<R;i++){
cin>>A>>B>>C;
E.push_back(Way(A,B,C));
E.push_back(Way(B,A,C));
}
for(int i=0;i<P;i++){
cin>>A>>B>>C;
E.push_back(Way(A,B,C));
}
for(int i=0;i<=T;i++){
dist[i]=INF;
}
dist[S]=0;
}
void Bellman_Ford(){
for(int i=1;i<T;i++){
for(int j=0;j<E.size();j++){
if( dist[E[j].u]!=INF && dist[E[j].u]+E[j].w<dist[E[j].v] ){
dist[E[j].v]=dist[E[j].u]+E[j].w;
//cout<<E[j].u<<" -> "<<E[j].v<<" : "<<dist[E[j].v]<<" = "<<dist[E[j].u]<<" + "<<E[j].w<<endl;
}
}
}
for(int i=1;i<=T;i++){
if(dist[i]==INF)
cout<<"NO PATH"<<endl;
else
cout<<dist[i]<<endl;
}
}
int main(int argc, char** argv) {
ReadInput();
Bellman_Ford();
return 0;
}
SPFA算法代码如下:
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
#define INF 65535
struct Town{
int v;
int w;
Town(){ }
Town(int vv,int ww):v(vv),w(ww){ }
};
int T,R,P,S;
int dist[25010];
vector< vector<Town> > G(25010);
int inq[25010];
void init(){
for(int i=0;i<=T;i++)
dist[i]=INF;
for(int i=1;i<=T;i++)
inq[i]=0;
dist[S]=0;
}
void ReadInput(){
cin>>T>>R>>P>>S;
int A,B,C;
for(int i=0;i<R;i++){
cin>>A>>B>>C;
G[A].push_back(Town(B,C));
G[B].push_back(Town(A,C));
}
for(int i=0;i<P;i++){
cin>>A>>B>>C;
G[A].push_back(Town(B,C));
}
init();
}
void SPFA(){
queue<int> Q;
Q.push(S);
inq[S]=1;
while(!Q.empty()){
int now=Q.front();
Q.pop();
inq[now]=0;
for(int i=0;i<G[now].size();i++){
int v=G[now][i].v;
if(dist[v]>dist[now]+G[now][i].w){
dist[v]=dist[now]+G[now][i].w;
if(inq[v]==1)
continue;
inq[v]=1;
Q.push(v);
}
}
}
for(int i=1;i<=T;i++){
if(dist[i]==INF)
cout<<"NO PATH"<<endl;
else
cout<<dist[i]<<endl;
}
}
int main(int argc, char** argv) {
ReadInput();
SPFA();
return 0;
}