UVA 10048 (Kruskal 的应用 解决 bottleneck 问题)

题目大意:

给你一幅图,图中的边带权,问你怎么找到图中两点u,v的一条路径,使得这条路径中权值最大的边是在所有uv路径中权值最大的边权值最小。有点绕,简单来说就是符合以下的一条公式约束

\min \limits_{p\epsilon (uv)} \max \limits_{i\epsilon p} d_i

其中uv代表点u v之间的所有路径,i表示路径中的一条边。

解题思路:

首先我们可以用kruskal得到MST,然后u 和 v之间存在的路径即为最优路径,然后我们遍历一遍路径就可以了,输出路径中的最大权重即可,这条路径我们可以通过在MST中DFS然后用存父亲的方法来获得。若MST中不存在u和v,那么我们可以输出no path. 

个人总结:

DFS写错了,真是要面壁思过...... 要记住节点遍历判重应该在for遍历子节点里面判重。一开始存父亲那里就是因为这里错了。

AC代码:

#include <bits/stdc++.h>
#define MAXN 200
#define UNVISITED 0
#define VISITED 1
using namespace std;
typedef vector<int > vi;
class UnionFind {
private:
	vi p, rank, setSize;
	int numSets;
public:
	UnionFind(int N) {
		p.assign(N, 0); rank.assign(N, 1); setSize.assign(N, 1);
		numSets = N; for (int i = 0; i<N; i++)p[i] = i;
	}
	int find_set(int i) { return p[i] == i ? i : p[i] = find_set(p[i]); }	//find the representative element(root of the tree)
	bool issameset(int i, int j) {
		//1 for same set
		return find_set(i) == find_set(j);
	}
	void Unionset(int i, int j) {
		if (!issameset(i, j)) {
			int x = find_set(i); int y = find_set(j);
			numSets--;
			if (rank[x] < rank[y]) {
				p[x] = y;
				setSize[y] += setSize[x];
			}
			else {
				p[y] = x;
				setSize[x] += setSize[y];
				if (rank[x] == rank[y])rank[x] ++;
			}
		}
	}
	int numDisjointsets() {
		return numSets;
	}
	int sizeOfSet(int i) {
		return setSize[find_set(i)];
	}
};
vector<vector<pair<int, double> > > gra(MAXN);
int dfs_parent[MAXN];
int suc_flag;
int qu, qv;
int dfs_flag[MAXN];
void DFS(int u) {
	// cerr<<u<<endl;
	if (u == qv) { suc_flag = 1; return; }	
	dfs_flag[u] = VISITED;
	for (int i = 0; i<(int)gra[u].size(); i++) {
		int nx = gra[u][i].first;
		if (dfs_flag[nx] == VISITED)continue;
		dfs_parent[nx] = u;
		DFS(nx);
	}
}
int main() {
	int c, s, q;
	int ca = 0;
	while (cin >> c >> s >> q && (c || s || q)) {
		ca++;
		vector<pair<double, pair<int, int>> > edges;
		for (int i = 0; i<s; i++) {
			int u, v;
			double wei;
			cin >> u >> v;
			cin >> wei;
			u -= 1;
			v -= 1;
			edges.push_back(make_pair(wei, make_pair(u, v)));
		}
		UnionFind djset(c);
		sort(edges.begin(), edges.end(), less<pair< double, pair<int, int>>>());
		for (int i = 0; i<MAXN; i++) {
			gra[i].erase(gra[i].begin(), gra[i].end());
		}
		int exi[MAXN];
		double Weight[MAXN][MAXN];
		memset(exi, 0, sizeof(exi));
		for (int i = 0; i<(int)edges.size(); i++) {
			int u = edges[i].second.first;
			int v = edges[i].second.second;
			double wei = edges[i].first;
			if (!djset.issameset(u, v)) {
				djset.Unionset(u, v);
				gra[u].emplace_back(v, wei);
				gra[v].emplace_back(u, wei);
				exi[u] = 1;
				exi[v] = 1;
				Weight[u][v] = wei;
				Weight[v][u] = wei;
			}
		}
		if (ca > 1)cout << endl;
		cout << "Case #" << ca << endl;
		for (int i = 0; i<q; i++) {

			cin >> qu >> qv;
			qu -= 1;
			qv -= 1;

			suc_flag = 0;
			memset(dfs_flag, UNVISITED, sizeof(dfs_flag));
			if (exi[qu])
				DFS(qu);
			

			if (!suc_flag)cout << "no path" << endl;
			else {
				double min_wei = -1;
				for (int u = qv; u != qu; u = dfs_parent[u]) {//dfs parent 
					//cerr << u << endl;
					double wei = Weight[u][dfs_parent[u]];
					min_wei = max(min_wei, wei);
				}
				cout << min_wei << endl;
			}
		}


	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值