道路和航路

问题描述

农夫约翰正在针对一个新区域的牛奶配送合同进行研究。他打算分发牛奶到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。



Bellan_Ford:

#include<bits/stdc++.h>
using namespace std;

int T,R,P,S;
int A,B,C;
int dp[30000];
const int inf = 0x9f9f9f;
int index = 0;

struct edge{
	int from,to,cost;
}e[150000];

void Bellan_Ford(int x)
{
	for(int i = 1; i <= T; i++){
		dp[i] = inf;
	}	
	
	dp[x] = 0;
	
	while(true){
		bool update = false;
		
		for(int i = 0; i < index; i++){
			if (dp[e[i].from] != inf && dp[e[i].to] > dp[e[i].from]+e[i].cost){
				dp[e[i].to] = dp[e[i].from]+e[i].cost;
				update = true;
			}
		}
		if (update == false)
			break;
	}
}

int main()
{
	cin >> T >> R >> P >> S;
	
	for(int i = 0; i < R; i++){
		cin >> A >> B >> C;
		e[index].from = A;
		e[index].to = B;
		e[index++].cost = C;
		e[index].from = B;
		e[index].to = A;
		e[index++].cost = C;
	}
	
	for(int i = 0; i < P; i++){
		cin >> A >> B >> C;
		e[index].from = A;
		e[index].to = B;
		e[index++].cost = C; 
	}
	
	Bellan_Ford(S);
	
	for(int i = 1; i <= T; i++){
		if (dp[i] == inf)
			printf("NO PATH\n");
		else 
			printf("%d\n",dp[i]); 
	}
		
	
	
	return 0;
}


SPFA:

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
const int MAXN = 25100;
const int INF=0x7FFFFFFF;
struct edge
{
    int to,weight;
};
int T,R,P,S;
vector<edge>adjmap[MAXN];//邻接表
bool in_queue[MAXN];//顶点是否在队列中
int in_sum[MAXN];//顶点入队的次数
int dist[MAXN];//源点到各点的最短路
int path[MAXN];//存储到达i的前一个顶点
int nodesum;  //顶点数
int edgesum;  //边数

bool spfa(int source)
{
    deque< int > dq;
    int i,j,x,to;
    for(int i = 1;i<=T;i++)//初始化函数
    {
         in_sum[i]= 0;
         in_queue[i]=false;
         dist[i]=INF;
         path[i]=-1;
    }
    dq.push_back(source);
    in_sum[source]++;
    dist[source]=0;        //到达本身的最短距离为0
    in_queue[source]= true;
    while(!dq.empty())
    {
        x = dq.front();
        dq.pop_front();
        in_queue[x]=false;
        for(int i = 0;i<adjmap[x].size();i++)
        {
            to = adjmap[x][i].to;
            if((dist[x]<INF) && ( dist[to]>dist[x]+adjmap[x][i].weight) )
            {
                dist[to] = dist[x]+adjmap[x][i].weight;
                path[to] = x;
                if(!in_queue[to])
                {
                    in_queue[to] = true;
                    in_sum[to]++;
                    if(in_sum[to] == nodesum) return false;
                    if(!dq.empty())
                    {
                       if(dist[to]>dist[dq.front()])  dq.push_back(to);
                       else dq.push_front(to);
                    } else dq.push_back(to);
             }
         }
      }
    }
    return true;
}

void print_path(int x)
{
    //输出最小的花费
    if(dist[x] == INF)//到不了的路径
        cout<<"NO PATH"<<endl;
    else cout<<dist[x]<<endl;
}

int main()
{

    edge temp;
    int s,e,w;
    scanf("%d %d %d %d",&T,&R,&P,&S);
    for(int i = 1;i<T;i++)
        adjmap[i].clear();//清空邻接表
    for(int i = 1; i<=R; i++)
    {
        scanf("%d %d %d",&s,&e,&w);
        temp.to = e;
        temp.weight = w;
        adjmap[s].push_back(temp);
        temp.to = s;
        adjmap[e].push_back(temp);//  公路的是双向的,需要放入两次
    }
    for(int i = 1;i<=P;i++)
    {
        scanf("%d %d %d",&s,&e,&w);
        temp.to = e;
        temp.weight = w;
        adjmap[s].push_back(temp);
    }
    if(spfa(S))
    {
        for(int i =1;i<=T; i++ )
             print_path(i);
    }
   // else cout<<"图中存在负权回路"<<endl;
    return 0;
}


猜你喜欢

转载自blog.csdn.net/Go_Accepted/article/details/80374764