1、最短路径(Shortest Path)
2、拓扑排序(Topological Sort)
3、关键路径(Critical Path)
1、题目描述:某省自从实行了很多年的畅通工程计划后,终于修建了很多路。不过路多了也不好,每次要从一个城镇到另一个城镇时,都有许多种道路方案可以选择,而某些方案要比另一些方案行走的距离要短很多。这让行人很困扰。现在,已知起点和终点,请你计算出要从起点到终点,最短需要行走多少距离。【2008浙大研究生复试热身赛(2)——全真模拟 hdu1874】
示例代码:
#include
#include
#include
#include
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 graph[MAX_N];
bool Node::operator<(const Node &n)const{
return distance < n.distance;
}
void Dijkstra(int s){
priority_queue 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,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。【浙江大学】
示例代码:
#include
#include
#include
#include
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 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 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的城市到其他城市的最短距离【上海交通大学】
示例代码:
#include
#include
#include
#include
#include
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 graph[MAX_N];
void Dijkstra(int s){
priority_queue 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?【北京大学】
示例代码:
#include
#include
#include
#include
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 graph[MAX_N];
void Dijkstra(int s, int c){
priority_queue 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】
示例代码:
#include
#include
#include
#include
using namespace std;
const int MAX_N = 100;
vector graph[MAX_N];
queue 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】
示例代码:
#include
#include
#include
#include
#include
using namespace std;
const int MAX_N = 501;
vector myVector[MAX_N];
priority_queue, greater > myQueue;//小值优先
int indegree[MAX_N];
vector 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】
示例代码:
#include
#include
#include
#include
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 topoList;
vector 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 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;