算法基础——图论(二)
目录:
- 基础知识
- 最短路径
- 拓扑排序
- 关键路径
- 应用实例
- 畅通工程续【2008浙大研究生复试热身赛(2)——全真模拟 hdu1874】
- 最短路径问题【浙江大学】
- 最短路径【上海交通大学】
- I Wanna Go Home【北京大学】
- Legal or Not【HDOJ Monthly Contest – 2010.03.06 hdu 3342】
- 确定比赛名次【杭电ACM集训队训练赛(VII) hdu 1285】
- Instruction Arrangement【2011 Alibaba-Cup Campus Contest hdu 4109】
一、基础知识
1、最短路径(Shortest Path)
- 定义:求图G(V, E)中某两个特定顶点间最短的路径长度。
- 常见算法:
- Dijkstra算法(贪心策略 + 优先队列)
- 集合S:已确定的顶点集合,初始只含源点s。
- 集合T:尚未确定的顶点集合。
- 算法反复从集合T中选择当前到源点s最近的顶点u,将u加入集合S,然后对所有从u发出的边进行松弛操作。
- 维护一个优先队列,将集合T中的顶点到源点s的距离,作为这些点的优先级,距离越低,优先级越高。那么只要从优先队列中取出队首元素,即可获得当前离源点s最近的顶点。
- Dijkstra算法(贪心策略 + 优先队列)
2、拓扑排序(Topological Sort)
- 定义:设有一个含有多条有向边(u, v)的有向无环图(Directed Acyclic Graph,DAG),将图中所有顶点排成一个线性序列,使得在该序列中顶点u都排在顶点v之前。满足该要求的顶点序列,称为满足拓扑序列。
- 方法:
- 从DAG图中选择入度为0的顶点,并输出。
- 从图中删除该入度为0的顶点及所有以它为起点的边。
- 重复上述过程直到当前图为空,或者图不存在入度为0的顶点。前者输出的序列就是拓扑序列;后者说明图中有环,不存在拓扑序列。
3、关键路径(Critical Path)
- 定义:
- AOE网(Activity On Edge Network):
- 顶点:事件
- 有向边:活动
- 边上权值:该活动持续的时间
- 源点:工程的开始顶点
- 汇点:工程的结束顶点
- 关键路径:从源点到汇点的所有路径中,具有最大路径长度的路径。
- 关键活动:关键路径上的活动。
- AOE网(Activity On Edge Network):
- 方法:
- 一个活动的全部先序活动的最晚完成时间便是该活动的最早开始时间。
- 一个活动的全部后序活动的最早开始时间减去该活动需要花费的时间,便是该活动的最晚开始时间。
- 根据拓扑序列逐一求出每个活动的最早开始时间,再根据拓扑序列的逆序列求出每个活动的最晚开始时间。所有活动中最早开始时间和最晚开始时间相同的活动称为关键活动,而所有活动中最早开始时间的最大值便是关键路径的长度。
二、应用实例
1、题目描述:某省自从实行了很多年的畅通工程计划后,终于修建了很多路。不过路多了也不好,每次要从一个城镇到另一个城镇时,都有许多种道路方案可以选择,而某些方案要比另一些方案行走的距离要短很多。这让行人很困扰。现在,已知起点和终点,请你计算出要从起点到终点,最短需要行走多少距离。【2008浙大研究生复试热身赛(2)——全真模拟 hdu1874】
- 输入格式:本题目包含多组数据,请处理到文件结束。每组数据第一行包含两个正整数N和M(0<N<200,0<M<1000),分别代表现有城镇的数目和已修建的道路的数目。城镇分别以0~N-1编号。接下来是M行道路信息。每一行有三个整数A,B,X(0<=A,B<N,A!=B,0<X<10000),表示城镇A和城镇B之间有一条长度为X的双向道路。再接下一行有两个整数S,T(0<=S,T<N),分别代表起点和终点。
- 输出格式:对于每组数据,请在一行里输出最短需要行走的距离。如果不存在从S到T的路线,就输出-1.
- 样例输入:
- 3 3
- 0 1 1
- 0 2 3
- 1 2 1
- 0 2
- 3 1
- 0 1 1
- 1 2
- 样例输出:
- 2
- -1
示例代码:
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
const int MAX_INT = 0x7fffffff;
const int MAX_N = 200;
struct Edge{
int to;
int length;
Edge(int t, int l):to(t), length(l){};
};
struct Node{
int number;
int distance;
Node(int n, int d):number(n), distance(d){};
bool operator<(const Node &n)const;
};
int dist[MAX_N];//源点到各点的距离
vector<Edge> graph[MAX_N];
bool Node::operator<(const Node &n)const{
return distance < n.distance;
}
void Dijkstra(int s){
priority_queue<Node> myQueue;
dist[s] = 0;
myQueue.push(Node(s, dist[s]));
while(!myQueue.empty()){
int u = myQueue.top().number;
myQueue.pop();
for(int i = 0; i < graph[u].size(); i++){
int v = graph[u][i].to;
int tmp = dist[u] + graph[u][i].length;
if(dist[v] > tmp){
dist[v] = tmp;
myQueue.push(Node(v, dist[v]));
}
}
}
}
int main(){
int n, m;
while(cin >> n >> m){
memset(graph, 0, sizeof(graph));
fill(dist, dist + n, MAX_INT);
int from, to, length;
for(int i = 0; i < m; i++){
cin >> from >> to >> length;
graph[from].push_back(Edge(to, length));
graph[to].push_back(Edge(from, length));
}
int source, finish;
cin >> source >> finish;
Dijkstra(source);
if(dist[finish] == MAX_INT){
cout << -1 << endl;
}else{
cout << dist[finish] << endl;
}
}
return 0;
}
2、题目描述:给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。【浙江大学】
- 输入格式:输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。