算法基礎——圖論(二)

算法基礎——圖論(二)

目錄:

  1. 基礎知識
    1. 最短路徑
    2. 拓撲排序
    3. 關鍵路徑
  2. 應用實例
    1. 暢通工程續【2008浙大研究生複試熱身賽(2)——全真模擬 hdu1874】
    2. 最短路徑問題【浙江大學】
    3. 最短路徑【上海交通大學】
    4. I Wanna Go Home【北京大學】
    5. Legal or Not【HDOJ Monthly Contest – 2010.03.06 hdu 3342】
    6. 確定比賽名次【杭電ACM集訓隊訓練賽(VII) hdu 1285】
    7. 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最近的頂點。

2、拓撲排序(Topological Sort)

  • 定義:設有一個含有多條有向邊(u, v)的有向無環圖(Directed Acyclic Graph,DAG),將圖中所有頂點排成一個線性序列,使得在該序列中頂點u都排在頂點v之前。滿足該要求的頂點序列,稱爲滿足拓撲序列。
  • 方法:
    • 從DAG圖中選擇入度爲0的頂點,並輸出。
    • 從圖中刪除該入度爲0的頂點及所有以它爲起點的邊。
    • 重複上述過程直到當前圖爲空,或者圖不存在入度爲0的頂點。前者輸出的序列就是拓撲序列;後者說明圖中有環,不存在拓撲序列。

3、關鍵路徑(Critical Path)

  • 定義:
    • 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。最後一行是兩個數 s,t;起點s,終點t。n和m爲0時輸入結束。(1<n<=1000, 0<m<100000, s != t)
  • 輸出格式:輸出一行有兩個數, 最短距離及其花費。
  • 樣例輸入:
    • 3 2
    • 1 2 5 6
    • 2 3 4 5
    • 1 3
    • 0 0
  • 樣例輸出:
    • 9 11

示例代碼:

#include <iostream>
#include <vector>
#include <queue>
#include <cstring>

using namespace std;

const int MAX_N = 1001;
const int MAX_INT = 0x7fffffff;

struct Edge{
	int to;
	int length;
	int cost;
	Edge(int t, int l, int c):to(t), length(l), cost(c){};
};

struct Node{
	int number;
	int distance;
	Node(int n, int d):number(n), distance(d){};
	bool operator<(const Node &n)const;
};

vector<Edge> graph[MAX_N];
int dist[MAX_N];
int cost[MAX_N];

bool Node::operator<(const Node &n)const{
	return distance < n.distance;
}

void Dijkstra(int s){
	priority_queue<Node> myQueue;
	dist[s] = 0;
	cost[s] = 0;
	myQueue.push(Node(s, 0));
	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 tmpDist = graph[u][i].length + dist[u];
			int tmpCost = graph[u][i].cost + cost[u];
			if(dist[v] == tmpDist && tmpCost < cost[v] 
				|| dist[v] > tmpDist){
				dist[v] = tmpDist;
				cost[v] = tmpCost;
				myQueue.push(Node(v, dist[v]));
			}
		}
	}
}

int main(){
	int n, m;
	while(cin >> n >> m && n != 0 && m != 0){
		memset(graph, 0, sizeof(graph));
		fill(dist, dist + n + 1, MAX_INT);
		fill(cost, cost + n + 1, MAX_INT);
		int from, to, length, c;
		for(int i = 0; i < m; i++){
			cin >> from >> to >> length >> c;
			graph[from].push_back(Edge(to, length, c));
			graph[to].push_back(Edge(from, length, c));
		}
		int startPoint, endPoint;
		cin >> startPoint >> endPoint;
		Dijkstra(startPoint);
		if(cost[endPoint] == MAX_INT || dist[endPoint] == MAX_INT){
			cout << "不可達" << endl;
		}
		cout << dist[endPoint] << " " << cost[endPoint] << endl;
	}
	return 0;
}

3、題目描述:N個城市,標號從0到N-1,M條道路,第K條道路(K從0開始)的長度爲2^K,求編號爲0的城市到其他城市的最短距離【上海交通大學】

  • 輸入格式:第一行兩個正整數N(2<=N<=100)M(M<=500),表示有N個城市,M條道路接下來M行兩個整數,表示相連的兩個城市的編號
  • 輸出格式:N-1行,表示0號城市到其他城市的最短路,如果無法到達,輸出-1,數值太大的以MOD 100000 的結果輸出。
  • 樣例輸入:
    • 4 4
    • 1 2
    • 2 3
    • 1 3
    • 0 1
  • 樣例輸出:
    • 8
    • 9
    • 11

示例代碼:

#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAX_N = 100;
const int MAX_INT = 0x7fffffff;
const int MOD = 100000;

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{
		return distance < n.distance;
	}
};

int dist[MAX_N];
int height[MAX_N];
int father[MAX_N];
vector<Edge> graph[MAX_N];

void Dijkstra(int s){
	priority_queue<Node> myQueue;
	dist[s] = 0;
	myQueue.push(Node(s, 0));
	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 len = graph[u][i].length + dist[u]; 
			if(len < dist[v]){
				dist[v] = len;
				myQueue.push(Node(v, dist[v]));
			}
		}
	}
}

int Find(int x){
	while(x != father[x]){
		x = father[x];
	}
	return father[x];
}

bool Union(int x, int y){
	x = Find(x);
	y = Find(y);
	if(x != y){
		if(height[x] > height[y]){
			father[y] = x;
		}else if(height[x] < height[y]){
			father[x] = y;
		}else{
			father[x] = y;
			height[y]++;
		}
		return true;
	}
	return false;
}

int main(){
	int n, m;
	while(cin >> n >> m){
		memset(graph, 0, sizeof(graph));
		for(int i = 0; i < MAX_N; i++){
			father[i] = i;
			height[i] = 0;
			dist[i] = MAX_INT;
		}
		int from, to, mul;
		for(int i = 0; i < m; i++){
			cin >> from >> to;
			if(i == 0){
				mul = 1;
			}else{
				mul = (mul * 2) % MOD;
			}
			if(Union(from, to)){
				graph[from].push_back(Edge(to, mul));
				graph[to].push_back(Edge(from, mul));
			}
		}
		Dijkstra(0);
		for(int i = 1; i <= n - 1; i++){
			if(dist[i] == MAX_INT){
				cout << -1 << endl;
			}else{
				cout << dist[i] % MOD << endl;
			}
		}
	}
	return 0;
}

4、題目描述:The country is facing a terrible civil war----cities in the country are divided into two parts supporting different leaders. As a merchant, Mr. M does not pay attention to politics but he actually knows the severe situation, and your task is to help him reach home as soon as possible.     "For the sake of safety,", said Mr.M, "your route should contain at most 1 road which connects two cities of different camp."     Would you please tell Mr. M at least how long will it take to reach his sweet home?【北京大學】

  • 輸入格式:The input contains multiple test cases.
    The first line of each case is an integer N (2<=N<=600), representing the number of cities in the country.
    The second line contains one integer M (0<=M<=10000), which is the number of roads.
    The following M lines are the information of the roads. Each line contains three integers A, B and T, which means the road between city A and city B will cost time T. T is in the range of [1,500].
    Next part contains N integers, which are either 1 or 2. The i-th integer shows the supporting leader of city i.
    To simplify the problem, we assume that Mr. M starts from city 1 and his target is city 2. City 1 always supports leader 1 while city 2 is at the same side of leader 2.
    Note that all roads are bidirectional and there is at most 1 road between two cities.
    Input is ended with a case of N=0.
  • 輸出格式:For each test case, output one integer representing the minimum time to reach home.
    If it is impossible to reach home according to Mr. M's demands, output -1 instead.
  • 樣例輸入:
    • 2
    • 1
    • 1 2 100
    • 1 2
    • 3
    • 3
    • 1 2 100
    • 1 3 40
    • 2 3 50
    • 1 2 1
    • 5
    • 5
    • 3 1 200
    • 5 3 150
    • 2 5 160
    • 4 3 170
    • 4 2 170
    • 1 2 2 2 1
    • 0
  • 樣例輸出:
    • 100
    • 90
    • 540

示例代碼:

#include <iostream>
#include <queue>
#include <vector>
#include <cstring>

using namespace std;

const int MAX_N = 601;
const int MAX_INT = 0x7fffffff;

struct Edge{
	int to;
	int length;
	Edge(int t, int l):to(t), length(l){};
};

struct Node{
	int number;
	int distance;
	bool operator<(const Node &n)const{
		return distance < n.distance;
	};
	Node(int n, int d):number(n), distance(d){};
};

int dist1[MAX_N]; //城市1到各點的距離
int dist2[MAX_N]; //城市2到各點的距離
int camp[MAX_N];
vector<Edge> graph[MAX_N];

void Dijkstra(int s, int c){
	priority_queue<Node> myQueue;
	int *dist = NULL;
	if(c == 1){
		dist = dist1;
	}else{
		dist = dist2;
	}
	dist[s] = 0;
	myQueue.push(Node(s, 0));
	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;
			if(c == camp[v]){
				int len = graph[u][i].length + dist[u];
				if(len < dist[v]){
					dist[v] = len;
					myQueue.push(Node(v, dist[v]));
				}
			}
		}
	}
}

void Init(int n){
	for(int i = 0; i <= n; i++){
		dist1[i] = MAX_INT;
		dist2[i] = MAX_INT;
	}
	memset(graph, 0, sizeof(graph));
	memset(camp, 0, sizeof(camp));
}

int main(){
	int n, road;
	while(cin >> n && n != 0){
		cin >> road;
		Init(n);
		int from, to, length;
		for(int i = 1; i <= road; i++){
			cin >> from >> to >> length;
			graph[from].push_back(Edge(to, length));
			graph[to].push_back(Edge(from, length));
		}
		for(int i = 1; i <= n; i++){
			cin >> camp[i];
		}
		Dijkstra(1, camp[1]);
		Dijkstra(2, camp[2]);
		int min = MAX_INT;
		for(int i = 1; i <= n; i++){
			if(dist1[i] == MAX_INT){ //找到第一個該陣營的點
				continue;
			}
			for(int j = 0; j < graph[i].size(); j++){
				if(dist2[graph[i][j].to] == MAX_INT){
					continue;
				}
				if(dist2[graph[i][j].to] + dist1[i] + graph[i][j].length < min){
					min = dist2[graph[i][j].to] + dist1[i] + graph[i][j].length;
				}
			}
		}
		if(min == MAX_INT){
			cout << -1 << endl;
		}else{
			cout << min << endl;
		}
	}
	return 0;
}

5、題目描述:ACM-DIY is a large QQ group where many excellent acmers get together. It is so harmonious that just like a big family. Every day,many "holy cows" like HH, hh, AC, ZT, lcc, BF, Qinz and so on chat on-line to exchange their ideas. When someone has questions, many warm-hearted cows like Lost will come to help. Then the one being helped will call Lost "master", and Lost will have a nice "prentice". By and by, there are many pairs of "master and prentice". But then problem occurs: there are too many masters and too many prentices, how can we know whether it is legal or not?
We all know a master can have many prentices and a prentice may have a lot of masters too, it's legal. Nevertheless,some cows are not so honest, they hold illegal relationship. Take HH and 3xian for instant, HH is 3xian's master and, at the same time, 3xian is HH's master,which is quite illegal! To avoid this,please help us to judge whether their relationship is legal or not.
Please note that the "master and prentice" relation is transitive. It means that if A is B's master ans B is C's master, then A is C's master.【HDOJ Monthly Contest – 2010.03.06 hdu 3342】

  • 輸入格式:The input consists of several test cases. For each case, the first line contains two integers, N (members to be tested) and M (relationships to be tested)(2 <= N, M <= 100). Then M lines follow, each contains a pair of (x, y) which means x is y's master and y is x's prentice. The input is terminated by N = 0.
    TO MAKE IT SIMPLE, we give every one a number (0, 1, 2,..., N-1). We use their numbers instead of their names.
  • 輸出格式:For each test case, print in one line the judgement of the messy relationship.If it is legal, output "YES", otherwise "NO".
  • 樣例輸入:
    • 3 2
    • 0 1
    • 1 2
    • 2 2
    • 0 1
    • 1 0
    • 0 0
  • 樣例輸出:
    • YES
    • NO

示例代碼:

#include <iostream>
#include <vector>
#include <cstring>
#include <queue>

using namespace std;

const int MAX_N = 100;
vector<int> graph[MAX_N];
queue<int> myQueue;
int indegree[MAX_N];

bool TopoSort(int n){
	int count = 0;
	for(int i = 0; i < n; i++){
		if(indegree[i] == 0){
			myQueue.push(i);
		}
	}
	while(!myQueue.empty()){
		int num = myQueue.front();
		myQueue.pop();
		count++;
		for(int i = 0; i < graph[num].size(); i++){
			indegree[graph[num][i]]--;
			if(indegree[graph[num][i]] == 0){
				myQueue.push(graph[num][i]);
			}
		}
	}
	return n == count;
}

int main(){
	int memberSize, relationSize;
	while(cin >> memberSize >> relationSize && memberSize != 0){
		int from, to;
		memset(graph, 0, sizeof(graph));
		memset(indegree, 0, sizeof(indegree));
		for(int i = 0; i < relationSize; i++){
			cin >> from >> to;
			graph[from].push_back(to);
			indegree[to]++;
		}
		if(TopoSort(memberSize)){
			cout << "YES" << endl;
		}else{
			cout << "NO" << endl;
		}
	}
	return 0;
}

6、題目描述:有N個比賽隊(1<=N<=500),編號依次爲1,2,3,。。。。,N進行比賽,比賽結束後,裁判委員會要將所有參賽隊伍從前往後依次排名,但現在裁判委員會不能直接獲得每個隊的比賽成績,只知道每場比賽的結果,即P1贏P2,用P1,P2表示,排名時P1在P2之前。現在請你編程序確定排名。【杭電ACM集訓隊訓練賽(VII) hdu 1285】

  • 輸入格式:輸入有若干組,每組中的第一行爲二個數N(1<=N<=500),M;其中N表示隊伍的個數,M表示接着有M行的輸入數據。接下來的M行數據中,每行也有兩個整數P1,P2表示即P1隊贏了P2隊。
  • 輸出格式:給出一個符合要求的排名。輸出時隊伍號之間有空格,最後一名後面沒有空格。其他說明:符合條件的排名可能不是唯一的,此時要求輸出時編號小的隊伍在前;輸入數據保證是正確的,即輸入數據確保一定能有一個符合要求的排名。
  • 樣例輸入:
    • 4 3
    • 1 2
    • 2 3
    • 4 3
  • 樣例輸出:
    • 1 2 4 3

示例代碼:

#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
#include <functional>

using namespace std;

const int MAX_N = 501;

vector<int> myVector[MAX_N];
priority_queue<int, vector<int>, greater<int> > myQueue;//小值優先
int indegree[MAX_N];
vector<int> result;

bool TopoSort(int n){
	for(int i = 1; i <= n; i++){
		if(indegree[i] == 0){
			myQueue.push(i);
		}
	}
	while(!myQueue.empty()){
		int num = myQueue.top();
		myQueue.pop();
		result.push_back(num);
		for(int i = 0; i < myVector[num].size(); i++){
			indegree[myVector[num][i]]--;
			if(indegree[myVector[num][i]] == 0){
				myQueue.push(myVector[num][i]);
			}
		}
	}
	return result.size() == n;
}

int main(){
	int n, m;
	while(cin >> n >> m){
		memset(indegree, 0, sizeof(indegree));
		memset(myVector, 0, sizeof(myVector));
		result.clear();
		int from, to;
		for(int i = 0; i < m; i++){
			cin >> from >> to;
			myVector[from].push_back(to);
			indegree[to]++;
		}
		if(TopoSort(n)){
			for(int i = 0; i < result.size(); i++){
				if(i != 0){
					cout << " ";
				}
				cout << result[i];
			}
			cout << endl;
		}
	}
	return 0;
}

7、題目描述:Ali has taken the Computer Organization and Architecture course this term. He learned that there may be dependence between instructions, like WAR (write after read), WAW, RAW.
If the distance between two instructions is less than the Safe Distance, it will result in hazard, which may cause wrong result. So we need to design special circuit to eliminate hazard. However the most simple way to solve this problem is to add bubbles(空指令) (useless operation), which means wasting time to ensure that the distance between two instructions is not smaller than the Safe Distance.
The definition of the distance between two instructions is the difference between their beginning times.
Now we have many instructions, and we know the dependent relations and Safe Distances between instructions. We also have a very strong CPU with infinite number of cores, so you can run as many instructions as you want simultaneity, and the CPU is so fast that it just cost 1ns to finish any instruction.
Your job is to rearrange the instructions so that the CPU can finish all the instructions using minimum time.【2011 Alibaba-Cup Campus Contest hdu 4109】

  • 輸入格式:The input consists several testcases.
    The first line has two integers N, M (N <= 1000, M <= 10000), means that there are N instructions and M dependent relations.
    The following M lines, each contains three integers X, Y , Z, means the Safe Distance between X and Y is Z, and Y should run after X. The instructions are numbered from 0 to N - 1.
  • 輸出格式:Print one integer, the minimum time the CPU needs to run.
  • 樣例輸入:
    • 5 2
    • 1 2 1
    • 3 4 1
  • 樣例輸出:
    • 2
  • 附註:In the 1st ns, instruction 0, 1 and 3 are executed; In the 2nd ns, instruction 2 and 4 are executed. So the answer should be 2.

示例代碼:

#include <iostream>
#include <vector>
#include <queue>
#include <cstring>

using namespace std;

const int MAX_INT = 0x7fffffff;
const int MAX_N = 1000;

struct Edge{
	int to;
	int length;
	Edge(int t, int l):to(t), length(l){};
};

vector<int> topoList;
vector<Edge> graph[MAX_N];
int earliest[MAX_N]; //最早開始時間
int latest[MAX_N];   //最晚開始時間
int indegree[MAX_N];

void Init(){
	topoList.clear();
	memset(graph, 0, sizeof(graph));
	for(int i = 0; i < MAX_N; i++){
		earliest[i] = 1;
		latest[i] = MAX_INT;
	}
	memset(indegree, 0, sizeof(indegree));
}

void TopoSort(int n){
	queue<int> myQueue;
	for(int i = 0; i < n; i++){
		if(indegree[i] == 0){
			myQueue.push(i);
		}
	}
	while(!myQueue.empty()){
		int u = myQueue.front();
		myQueue.pop();
		topoList.push_back(u);
		for(int i = 0; i < graph[u].size(); i++){
			int v = graph[u][i].to;
			int len = graph[u][i].length;
			earliest[v] = max(earliest[u] + len, earliest[v]);
			indegree[v]--;
			if(indegree[v] == 0){
				myQueue.push(v);
			}
		}
	}
}

void CriticalPath(int n){
	for(int i = topoList.size() - 1; i >= 0; i--){
		int u = topoList[i];
		if(graph[u].size() == 0){
			latest[u] = earliest[u];
			continue;
		}
		for(int j = 0; j < graph[u].size(); j++){
			int v = graph[u][j].to;
			int len = graph[u][j].length;
			latest[u] = min(latest[v] - len, latest[u]);
		}
	}
}

int main(){
	int n, m;
	while(cin >> n >> m){
		Init();
		int from, to, distance;
		for(int i = 0; i < m; i++){
			cin >> from >> to >> distance;
			graph[from].push_back(Edge(to, distance));
			indegree[to]++;
		}
		TopoSort(n);
		CriticalPath(n);
		int answer = 0;
		for(int i = 0; i < n; i++){
			answer = max(answer, earliest[i]);
		}
		cout << answer << endl;
	}
	return 0;
}

參考文獻:

[1]楊澤邦、趙霖. 計算機考研——機試指南(第2版). [M]北京:電子工業出版社,2019.11;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章