NEFU-最短路,acm暑期培训

                               

目录

                               

                                 A - 最短路

Problem - 2544 (hdu.edu.cn)

朴素版Dijkstra算法

优化版Dijkstra

 Bellman_ford版

       H - Delay Constrained Maximum Capacity Path

Problem - 1839 (hdu.edu.cn)

二分+Dijkstra版

二分+spfa版


                                 A - 最短路

Problem - 2544 (hdu.edu.cn)

在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt。但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗?
 

Input

输入包括多组数据。每组数据第一行是两个整数N、M(N<=100,M<=10000),N表示成都的大街上有几个路口,标号为1的路口是商店所在地,标号为N的路口是赛场所在地,M则表示在成都有几条路。N=M=0表示输入结束。接下来M行,每行包括3个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。
输入保证至少存在1条商店到赛场的路线。

Output

对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间

Sample

InputcopyOutputcopy
2 1
1 2 3
3 3
1 2 5
2 3 5
3 1 2
0 0
3
2

朴素版Dijkstra算法

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long LL;
const int N = 100 + 5;
int G[N][N], d[N], v[N];
int n, m;

void Dijkstra() {
	memset(d, 0x3f3f3f3f, sizeof(d));
	d[1] = 0;
	for (int i = 1; i <= n; i++) {
		int x = -1;
		for (int j = 1; j <= n; j++) {
			if (!v[j] && (x == -1 || d[x] > d[j])) {
				x = j;
			}
		}
		v[x] = 1;
		for (int j = 1; j <= n; j++) {
			if (!v[j]) {
				d[j] = min(d[j], d[x] + G[x][j]);
			}
		}
	}
}

int main() {
	while (cin >> n >> m) {
		if (n == 0 && m == 0)
			break;
		memset(G, 0x3f3f3f3f, sizeof(G));
		for (int i = 1; i <= n; i++)
			G[i][i] = 0;
		memset(v, 0, sizeof(v));
		for (int i = 1, a, b, t; i <= m; i++) {
			scanf("%d%d%d", &a, &b, &t);
			G[b][a] = G[a][b] = min(G[a][b], t);
		}
		Dijkstra();
		cout << d[n] << endl;
	}
	return 0;
}

优化版Dijkstra

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long LL;
const int N = 100 + 5;
int n, m;
typedef struct st {
	int e, w;
}st;
vector<st>G[N];
int d[N], v[N];

bool operator > (const st& a, const st& b) {
	return a.w > b.w;
}

void Dijkstra() {
	memset(d, 0x3f3f3f3f, sizeof(d));
	memset(v, 0, sizeof(v));
	d[1] = 0;
	priority_queue<st, vector<st>, greater<st>>q;
	q.push({ 1,0 });
	int t;
	while (!q.empty()) {
		t = q.top().e;
		q.pop();
		if (v[t])
			continue;
		v[t] = 1;
		for (int i = 0; i < G[t].size(); i++) {
			int j = G[t][i].e;
			if (d[j] > d[t] + G[t][i].w) {
				d[j] = d[t] + G[t][i].w;
				q.push({ j,d[j] });
			}
		}
	}
}

int main() {
	while (cin >> n >> m) {
		if (n == 0 && m == 0)
			break;
		for (int i = 1,a,b,t; i <= m; i++) {
			scanf("%d%d%d", &a, &b, &t);
			G[a].push_back({ b,t });
			G[b].push_back({ a,t });
		}
		Dijkstra();
		cout << d[n] << endl;
		for (int i = 1; i <= n; i++)
			G[i].clear();
	}
	return 0;
}

 Bellman_ford版

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long LL;
const int N = 100 + 5, M = 1e4 + 5;
int n, m;
struct edge {
	int u, e, w;
}edge[M];
int d[N], backup[N];

void Bellman_ford() {
	memset(d, 0x3f3f3f3f, sizeof(d));
	d[1] = 0;
	for (int i = 1; i <= m; i++) {
		memcpy(backup, d, sizeof(d));
		for (int j = 1,a,b,t; j <= m; j++) {
			a = edge[j].e, b = edge[j].u, t = edge[j].w;
			if (d[a] > backup[b] + t) {
				d[a] = backup[b] + t;
			}
			if (d[b] > backup[a] + t)
				d[b] = backup[a] + t;
		}
	}
}

int main() {
	while (cin >> n >> m) {
		if (n == 0 && m == 0)
			break;
		for (int i = 1; i <= m; i++) {
			scanf("%d%d%d", &edge[i].u, &edge[i].e, &edge[i].w);
		}

		Bellman_ford();
		cout << d[n] << endl;
	}
	return 0;
}

       H - Delay Constrained Maximum Capacity Path

Problem - 1839 (hdu.edu.cn)

Consider an undirected graph with N vertices, numbered from 1 to N, and M edges. The vertex numbered with 1 corresponds to a mine from where some precious minerals are extracted. The vertex numbered with N corresponds to a minerals processing factory. Each edge has an associated travel time (in time units) and capacity (in units of minerals). It has been decided that the minerals which are extracted from the mine will be delivered to the factory using a single path. This path should have the highest capacity possible, in order to be able to transport simultaneously as many units of minerals as possible. The capacity of a path is equal to the smallest capacity of any of its edges. However, the minerals are very sensitive and, once extracted from the mine, they will start decomposing after T time units, unless they reach the factory within this time interval. Therefore, the total travel time of the chosen path (the sum of the travel times of its edges) should be less or equal to T.

Input

The first line of input contains an integer number X, representing the number of test cases to follow. The first line of each test case contains 3 integer numbers, separated by blanks: N (2 <= N <= 10.000), M (1 <= M <= 50.000) and T (1 <= T <= 500.000). Each of the next M lines will contain four integer numbers each, separated by blanks: A, B, C and D, meaning that there is an edge between vertices A and B, having capacity C (1 <= C <= 2.000.000.000) and the travel time D (1 <= D <= 50.000). A and B are different integers between 1 and N. There will exist at most one edge between any two vertices.

Output

For each of the X test cases, in the order given in the input, print one line containing the highest capacity of a path from the mine to the factory, considering the travel time constraint. There will always exist at least one path between the mine and the factory obbeying the travel time constraint.

Sample

InputcopyOutputcopy
2 
2 1 10 
1 2 13 10
4 4 20 
1 2 1000 15 
2 4 999 6 
1 3 100 15 
3 4 99 4 
13 
99 

分析与总结:

因为每条路径的容量取决于这条路径中所有边中的最小容量,所以我们可以以此枚举最小容量。
但是如果一个一个容量的枚举,那明显效率太低了。

通过分析,可以看出,如果最低容量越大,那么符合要求的路径就越少,所以,根据容量的大小,路径数量是单调的。

有了单调性,就可以利用二分法了。

只要把容量从大到小进行排序,然后二分之,很快便能算出答案。
 

 这里的二分我最开始没有想到。这里的二分很妙,二分与最短路结合,真的太妙了。

二分+Dijkstra版


#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>

using namespace std;
typedef long long LL;
const int N = 1e4 + 5, M=5e4 + 5;
LL n, m,T;
typedef struct st {
	LL e, c, w;
}st;
vector<st>G[N];
LL d[N], v[N];
LL cap[M];
typedef struct stt {
	LL e, w;
}stt;

bool cmp(const LL& a, const LL& b){
	return a < b;
}

bool operator > (const stt& a, const stt& b) {
	return a.w > b.w;
}

LL Dijkstra(LL in) {
	memset(d, 0x3f3f3f3f3f3f3f3f, sizeof(d));
	memset(v, 0, sizeof(v));
	d[1] = 0;
	priority_queue<stt, vector<stt>, greater<stt>>q;
	q.push({ 1,0 });
	LL t;
	while (!q.empty()) {
		t = q.top().e;
		q.pop();
		if (v[t])
			continue;
		v[t] = 1;
		for (int i = 0; i < G[t].size(); i++) {
			if (G[t][i].c < in)
				continue;
			int j = G[t][i].e;
			if (d[j] > d[t] + G[t][i].w) {
				d[j] = d[t] + G[t][i].w;
				q.push({ j,d[j] });
			}
		}
	}
	return d[n];
}

int main() {
	int X;
	cin >> X;
	while (X--) {
		cin >> n >> m >> T;
		for (int i = 0; i <= n; i++) {
			G[i].clear();
		}
		memset(cap, 0, sizeof(cap));
		for (int i = 1,a,b,c,t; i <= m; i++) {
			scanf("%d%d%d%d", &a, &b, &c, &t);
			G[a].push_back({ b,c,t });
			G[b].push_back({ a,c,t });
			cap[i] = c;
		}
		sort(cap + 1, cap + 1 + m, cmp);
		
		int l = 1, r = m, mid, ans;
		LL t;
		while (l <= r) {
			mid = l + (r - l) / 2;
			t = Dijkstra(cap[mid]);
			if (t==0x3f3f3f3f3f3f3f3f||t > T) {
				//这里是r = mid - 1,不是l = mid + 1千万别搞混了,我这里错了好几次
                r = mid - 1;
			}
			else {
				ans = mid;
				l = mid + 1;
			}
		}
		//cout << ans << endl;
		cout << cap[ans] << endl;
	}

	return 0;
}

二分+spfa版

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long LL;
const int N = 1e4 + 5,M=5e4+5;
int n, m, T;
int d[N], v[N], cap[M];
typedef struct st {
	int e, c, w;
}st;
vector<st>G[N];

int cmp(const int &a,const int&b) {
	return a < b;
}

int spfa(int in) {
	memset(d, 0x3f3f3f3f, sizeof(d));
	memset(v, 0, sizeof(v));
	d[1] = 0;
	v[1] = 1;
	queue < int>q;
	q.push(1);
	int t;
	while (!q.empty()) {
		t = q.front();
		q.pop();
		v[t] = 0;
		for (int i = 0,j,dist; i < G[t].size(); i++) {
			if (G[t][i].c >= in) {
				j = G[t][i].e;
				dist = G[t][i].w;
				if (d[j] > d[t] + dist) {
					d[j] = d[t] + dist;
					if (v[j] == 0) {
						v[j] = 1;
						q.push(j);
					}
				}
			}
		}
	}
	return d[n];
}

int main() {
	int X;
	cin >> X;
	while (X--) {
		cin >> n >> m >> T;
		for (int i = 0; i <= n; i++) {
			G[i].clear();
		}
		for (int i = 1,a,b,c,w; i <= m; i++) {
			scanf("%d%d%d%d", &a, &b, &c, &w);
			G[a].push_back({ b,c,w });
			G[b].push_back({ a,c,w });
			cap[i] = c;
		}

		sort(cap + 1, cap + 1 + m, cmp);

		int l = 1, r = m, mid, ans,t;
		while (l <= r) {
			mid = l + (r - l) / 2;
			t = spfa(cap[mid]);
			if ( t > T) {
				r = mid - 1;
			}
			else {
				ans = mid;
				l = mid + 1;
			}
		}
		cout << cap[ans] << endl;
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值