图论day64 :最短路径算法 | SPFA(Bellman_ford的队列优化版)、94.城市间货物运输 I(卡码网)【SPFA算法 + 邻接表优化】、95.城市间货物运输 II(判断负权回路)、96.城市间货物运输 III【已知有负权回路,该如何计算】、Bellman_ford算法思维导图汇总
SPFA(Bellman_ford的队列优化版)
94.城市间货物运输 I(卡码网)【SPFA算法 + 邻接表优化】
题目描述
某国为促进城市间经济交流,决定对货物运输提供补贴。共有 n 个编号为 1 到 n 的城市,通过道路网络连接,网络中的道路仅允许从某个城市单向通行到另一个城市,不能反向通行。
网络中的道路都有各自的运输成本和政府补贴,道路的权值计算方式为:运输成本 - 政府补贴。权值为正表示扣除了政府补贴后运输货物仍需支付的费用;权值为负则表示政府的补贴超过了支出的运输成本,实际表现为运输过程中还能赚取一定的收益。
请找出从城市 1 到城市 n 的所有可能路径中,综合政府补贴后的最低运输成本。如果最低运输成本是一个负数,它表示在遵循最优路径的情况下,运输过程中反而能够实现盈利。
城市 1 到城市 n 之间可能会出现没有路径的情况,同时保证道路网络中不存在任何负权回路。
输入描述
第一行包含两个正整数,第一个正整数 n 表示该国一共有 n 个城市,第二个整数 m 表示这些城市中共有 m 条道路。
接下来为 m 行,每行包括三个整数,s、t 和 v,表示 s 号城市运输货物到达 t 号城市,道路权值为 v (单向图)。
输出描述
如果能够从城市 1 到连通到城市 n, 请输出一个整数,表示运输成本。如果该整数是负数,则表示实现了盈利。如果从城市 1 没有路径可达城市 n,请输出 “unconnected”。
输入示例
6 7
5 6 -2
1 2 1
5 3 1
2 5 2
2 4 -3
4 6 4
1 3 5
输出示例
1
提示信息
示例中最佳路径是从 1 -> 2 -> 5 -> 6,路上的权值分别为 1 2 -2,最终的最低运输成本为 1 + 2 + (-2) = 1。
示例 2:
4 2
1 2 -1
3 4 -1
在此示例中,无法找到一条路径从 1 通往 4,所以此时应该输出 “unconnected”。
数据范围:
1 <= n <= 1000;
1 <= m <= 10000;
-100 <= v <= 100;
#include <iostream>
#include <vector>
#include <queue>
#include <list>
#include <climits>
using namespace std;
struct Edge
{
int to;
int val;
Edge(int t,int v):to(t),val(v){}
};
int main()
{
int n,m,p1,p2,val;
cin>>n>>m;
vector<list<Edge>> grid(n+1);
vector<bool> isInQueue(n+1,false);
for(int i=0;i<m;i++)
{
cin>>p1>>p2>>val;
grid[p1].push_back(Edge(p2,val));
}
int start=1;
int end=n;
vector<int> minDist(n+1,INT_MAX);
minDist[start]=0;
queue<int> que;
que.push(start);
isInQueue[start]=true;
while(!que.empty())
{
int node=que.front();
que.pop();
isInQueue[node]=false;
for(Edge edge:grid[node])
{
int from=node;
int to=edge.to;
int value=edge.val;
if(minDist[to]>minDist[from]+value)//这里不用限制minDist[from]!=INT_MAX
{
minDist[to]=minDist[from]+value;
if(isInQueue[to]==false)
{
que.push(to);
isInQueue[to]=true;
}
}
}
}
if (minDist[end] == INT_MAX) cout << "unconnected" << endl; // 不能到达终点
else cout << minDist[end] << endl;
}
95.城市间货物运输 II【判断负权回路】
题目描述
某国为促进城市间经济交流,决定对货物运输提供补贴。共有 n 个编号为 1 到 n 的城市,通过道路网络连接,网络中的道路仅允许从某个城市单向通行到另一个城市,不能反向通行。
网络中的道路都有各自的运输成本和政府补贴,道路的权值计算方式为:运输成本 - 政府补贴。权值为正表示扣除了政府补贴后运输货物仍需支付的费用;权值为负则表示政府的补贴超过了支出的运输成本,实际表现为运输过程中还能赚取一定的收益。
然而,在评估从城市 1 到城市 n 的所有可能路径中综合政府补贴后的最低运输成本时,存在一种情况:**图中可能出现负权回路。**负权回路是指一系列道路的总权值为负,这样的回路使得通过反复经过回路中的道路,理论上可以无限地减少总成本或无限地增加总收益。为了避免货物运输商采用负权回路这种情况无限的赚取政府补贴,算法还需检测这种特殊情况。
请找出从城市 1 到城市 n 的所有可能路径中,综合政府补贴后的最低运输成本。同时能够检测并适当处理负权回路的存在。
城市 1 到城市 n 之间可能会出现没有路径的情况
输入描述
第一行包含两个正整数,第一个正整数 n 表示该国一共有 n 个城市,第二个整数 m 表示这些城市中共有 m 条道路。
接下来为 m 行,每行包括三个整数,s、t 和 v,表示 s 号城市运输货物到达 t 号城市,道路权值为 v。
输出描述
如果没有发现负权回路,则输出一个整数,表示从城市 1
到城市 n
的最低运输成本(包括政府补贴)。如果该整数是负数,则表示实现了盈利。如果发现了负权回路的存在,则输出 “circle”。如果从城市 1 无法到达城市 n,则输出 “unconnected”。
输入示例
4 4
1 2 -1
2 3 1
3 1 -1
3 4 1
输出示例
circle
提示信息
路径中存在负权回路,从 1 -> 2 -> 3 -> 1,总权值为 -1,理论上货物运输商可以在该回路无限循环赚取政府补贴,所以输出 “circle” 表示已经检测出了该种情况。
数据范围:
1 <= n <= 1000;
1 <= m <= 10000;
-100 <= v <= 100;
#include <iostream>
#include <vector>
#include <list>
#include <climits>
using namespace std;
int main()
{
int n,m,p1,p2,val;
cin>>n>>m;
vector<vector<int>> grid;
for(int i=0;i<m;i++)
{
cin>>p1>>p2>>val;
grid.push_back({p1,p2,val});
}
int start=1;
int end=n;
vector<int> minDist(n+1,INT_MAX);
minDist[start]=0;
bool flag=false;
for(int i=1;i<=n;i++)
{
for(vector<int> &side:grid)
{
int from=side[0];
int to=side[1];
int price=side[2];
if(i<n)
{
if(minDist[from]!=INT_MAX&&minDist[to]>minDist[from]+price)
minDist[to]=minDist[from]+price;
}
else
{
if(minDist[from]!=INT_MAX&&minDist[to]>minDist[from]+price)
flag=true;
}
}
}
if(flag) cout<<"circle"<<endl;
else if (minDist[end] == INT_MAX)
{
cout << "unconnected" << endl;
}
else
{
cout << minDist[end] << endl;
}
}
96.城市间货物运输 III【已知有负权回路,该如何计算】
题目描述
某国为促进城市间经济交流,决定对货物运输提供补贴。共有 n 个编号为 1 到 n 的城市,通过道路网络连接,网络中的道路仅允许从某个城市单向通行到另一个城市,不能反向通行。
网络中的道路都有各自的运输成本和政府补贴,**道路的权值计算方式为:运输成本 - 政府补贴。**权值为正表示扣除了政府补贴后运输货物仍需支付的费用;权值为负则表示政府的补贴超过了支出的运输成本,实际表现为运输过程中还能赚取一定的收益。
请计算在最多经过 k 个城市的条件下,从城市 src 到城市 dst 的最低运输成本。
输入描述
第一行包含两个正整数,第一个正整数 n 表示该国一共有 n 个城市,第二个整数 m 表示这些城市中共有 m 条道路。
接下来为 m 行,每行包括三个整数,s、t 和 v,表示 s 号城市运输货物到达 t 号城市,道路权值为 v。
最后一行包含三个正整数,src、dst、和 k,src 和 dst 为城市编号,从 src 到 dst 经过的城市数量限制。
输出描述
输出一个整数,表示从城市 src 到城市 dst 的最低运输成本,如果无法在给定经过城市数量限制下找到从 src 到 dst 的路径,则输出 “unreachable”,表示不存在符合条件的运输方案。
输入示例
6 7
1 2 1
2 4 -3
2 5 2
1 3 5
3 5 1
4 6 4
5 6 -2
2 6 1
输出示例
0
提示信息
从 2 -> 5 -> 6 中转一站,运输成本为 0。
1 <= n <= 1000;
1 <= m <= 10000;
-100 <= v <= 100;
#include <iostream>
#include <vector>
#include <list>
#include <climits>
using namespace std;
int main()
{
int n,m,p1,p2,val,k,src,dst;
cin>>n>>m;
vector<vector<int>> grid;
for(int i=0;i<m;i++)
{
cin>>p1>>p2>>val;
grid.push_back({p1,p2,val});
}
cin>>src>>dst>>k;
vector<int> minDist(n+1,INT_MAX);
minDist[src]=0;
vector<int> minDist_copy(n+1);
for(int i=1;i<=k+1;i++)
{
minDist_copy = minDist;
for(vector<int> &side:grid)
{
int from=side[0];
int to=side[1];
int price=side[2];
if(minDist_copy[from]!=INT_MAX&&minDist[to]>minDist_copy[from]+price)
minDist[to]=minDist_copy[from]+price;
}
}
if(minDist[dst]==INT_MAX) cout<<"unreachable"<<endl;
else cout<<minDist[dst]<<endl;
}