UVA 11354 Bond

题意:邦德要从一个城市到达另一个城市,但是每条边都有危险值,bond需要找出一条路,是的路上的危险值最小,但是从u到v的一条路的危险值取决于这条路上的边的危险值的最大值。也就是说需要找到一条路,使得该路上最长边最短,就是最小瓶颈生成树了

因为要多次访问,所以的话先预处理。因为最短路一定是在最小生成树里的,所以,先求最小生成树,然后把最小生成树改成有根树,有根树中引入层的概念,根据到根节点的距离,分层,如果两个点在同一层,就可以从两边同时找向上层遍历来,因为从两边遍历,所以更省时间,因为层数相同,所以任意两点在向上层遍历的时候必会有祖先相同(此时两点之间就找到了一条路了,而且此路必然就是所求的路了)的情况,此时就找左边点到相同祖先的路的最大边,以及右边的点到相同祖先节点的路的最大边,然后取最大值

 这题的话还能用二进制来优化时间,但是看不懂,所以就没用二进制

#include<stdio.h>
#include<string.h>
#include<queue>
#define MEM(x,y) memset(x,y,sizeof(x))
#define max(x,y) x<y?y:x
#define INF 51000
#define Max 1000000000
using namespace std;
struct edge		//整个图中的边
{
	friend bool operator <(edge x,edge y)
	{
		return x.len > y.len;
	}
	int x,y,len;
};
struct MSTedge	//最小生成树中的边
{
	int x,len,next;
}MSTe[2*INF];
int n,m,q;
int cnt;
int parent[INF],head[INF];	//head[]存以该点为起点的边在边集中的下标
priority_queue<edge>Q;		//存储整个图的边

//将MST变成有根树时使用的变量
int father[INF],dis[INF];			//fatehr[]用来记录该节点在有根树中的父节点,dis[]用来记录该点的层数
int cost[INF];				//cost[]用来记录该点到其父节点的距离

void addMSTedge(int x,int y,int len)
{
	MSTe[cnt].x = y;
	MSTe[cnt].len = len;
	MSTe[cnt].next = head[x];
	head[x] = cnt++;
}
int root(int x)
{
	if(parent[x] == -1)return x;
	else return parent[x] = root(parent[x]);
}

void merge(int x,int y)
{
	x = root(x);
	y = root(y);
	parent[x] = y;
}

void kruskal()
{
	cnt = 0;	//MST中边的下标
	int jishu = 0;	//计数
	while(!Q.empty())
	{
		edge t = Q.top();
		Q.pop();
		if(root(t.x) != root(t.y))
		{
			merge(t.x,t.y);
			jishu++;
			addMSTedge(t.x,t.y,t.len);
			addMSTedge(t.y,t.x,t.len);
		}
		if(jishu == n-1)	//MST中有了n-1条边
			break;
	}
}

void roottree()		//建立有根树
{
	int flag[INF];	//标记MST的该点是够遍历过
	MEM(flag,0);
	MEM(dis,0);
	MEM(father,-1);
	MEM(cost,0);
	queue<int>que;
	while(!que.empty())
		que.pop();
	que.push(1);		//以1为根利用bfs建立有根树
	flag[1] = 1;
	dis[1] = 0;
	while(!que.empty())
	{
		int t = que.front();
		que.pop();
		for(int i = head[t] ; i != -1; i = MSTe[i].next)
		{
			int temp = MSTe[i].x;		//该边的末点
			if(flag[temp] == 0)
			{
				flag[temp] = 1;		//标记该点已经遍历过了	
				father[temp] = t;	//更新父节点
				cost[temp] = MSTe[i].len;
				dis[temp] = dis[t] + 1;	//层数加一
				que.push(temp);
			}
		}
	}
}

void solve(int x,int y)
{
	int maxx = -1,maxy = -1;	//初始化两个点到根节点的路的最大边权
	if(dis[x] > dis[y])	//如果x的层数大于y的,即x在y下面
	{
		while(dis[x] > dis[y])
		{
			maxx = max(maxx,cost[x]);	//更新这条路的最大边权
			x = father[x];
		}
	}
	else if(dis[y] > dis[x])
	{
		while(dis[y] > dis[x])
		{
			maxy = max(maxy,cost[y]);	//更新这条路的最大边权
			y = father[y];
		}
	}
	//此时x,y层数相同,然后就可以两边同时向上遍历,更快
	while(x != y)	//当x,y的祖先相同时,就结束算法
	{
		maxx = max(maxx,cost[x]);	//两个节点同时往上走
		x = father[x];
		maxy = max(maxy,cost[y]);
		y = father[y];
	}
	printf("%d\n",max(maxx,maxy));
}

int main()
{
	int nnn= 0;
	while(scanf("%d%d",&n,&m) != EOF)
	{
		if(nnn++ != 0)
			printf("\n");
		MEM(parent,-1);
		MEM(head,-1);
		MEM(MSTe,0);
		while(!Q.empty())
			Q.pop();
		for(int i = 1; i <= m ; i++)	
		{
			edge t;
			scanf("%d%d%d",&t.x,&t.y,&t.len);
			Q.push(t);
		}
		kruskal();		//求最小生成树MST
		roottree();		//把MST变成有根树

		scanf("%d",&q);
		while(q--)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			solve(x,y);		
		}
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值