uva 11354 bond 最小瓶颈路

题意:有n座城市通过m条双向道路相连,每条道路都有一个危险系数。你的任务是回答若干的询问,每个询问包含一个起点s和一个终点t,要求找到一条从s到t的路,使得途径所有边的最大危险系数最小

输出最优路线上所有边的危险系数的最大值。不同数据之间输出一个空行

给的数据很大,没法直接保存节点之间路线的危险系数的最大值。

思路是求最小生成树,然后转化成有根树,设s与t最早的公共祖先是p则s到t的路就是 s-p-t,求出s-p的危险系数最大值和p-t危险系数最大值比较即可。为了省时,首先使s和t的深度相同,就是求s-s'的危险系数最大值,然后s'和t深度相同就可以一起向上提,一直到一个公共节点。

这里一个一个向上提就太慢,所以用了类似二进制的方法,cost[i][j]指的是i节点到它上面第 2^j个祖先的危险系数最大值,因为每个长度都可以用二进制表示出来,就把s-p分成了几部分。

wa了8次,坑在重边上面

还得多练这种题

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
typedef struct zzz
{
	int from,to,dan;
	bool v;
	friend bool operator < (zzz a,zzz b)
	{
		return a.dan<b.dan;
	}
} Edge;
Edge edge[100005];
vector<int> G[50005];
int n,m,p[50005][22],cost[50005][22],fa[50005],bit,father[50005];
bool visit[50005];
#define INF 10000000
int root(int x)
{
	if(father[x]==-1) return x;
	return father[x]=root(father[x]);
}
bool merge(int a,int b)
{
	int anc_a=root(a);
	int anc_b=root(b);
	if(anc_a!=anc_b)
	{<span style="font-family: Arial, Helvetica, sans-serif;">//并查集的确是anc_a和anc_b连起来,但实际是a和b相连</span>
		father[anc_a]=anc_b;
		G[b].push_back(a);
		G[a].push_back(b);
		return 1;
	}
	return 0;
}
void kruskal()
{
	sort(edge,edge+m);
	for(int i=0;i<=m-1;i++)
	{
		if(merge(edge[i].from,edge[i].to)) edge[i].v=1;
		else edge[i].v=0;
	}
	return;
}
void find_ancestor()
{//首先求出每个节点低级的祖先,再根据低级祖先求高级祖先(先知道每个人的爸爸是谁,然后就知道每个人的爷爷是谁了)
	for(int i=1;(1<<i)<=n;i++)
		for(int j=0;j<=n-1;j++)
		{
			int anc=p[j][i-1];
			if(anc==-1||p[anc][i-1]==-1) continue;
			p[j][i]=p[anc][i-1];
			cost[j][i]=max(cost[j][i-1],cost[anc][i-1]);
		}
	return;
}
void dfs(int x,int far,int father)
{//无根树转有根树,求每个节点的深度和父亲节点
	fa[x]=far;
	p[x][0]=father;
	for(vector<int>::iterator it=G[x].begin();it!=G[x].end();it++)
	{
		if(!visit[*it])
		{
			visit[*it]=1;
			dfs(*it,far+1,x);
		}
	}
	return;
}
int solve(int node1,int node2)
{
	int differ=fa[node1]-fa[node2],ans=-INF;
	for(int i=bit;i>=0;i--)
	{//将深的那个节点提到相同深度
		if((1<<i)<=differ)
		{
			differ-=(1<<i);
			ans=max(ans,cost[node1][i]);
			node1=p[node1][i];
		}
	}
	for(int i=bit;i>=0;i--)
	{//二进制,找公共祖先,但不会找到,除非一开始两个节点就重合,否则得到的是公共祖先的两个儿子节点
		if(p[node1][i]!=p[node2][i])
		{
			ans=max(ans,max(cost[node1][i],cost[node2][i]));
			node1=p[node1][i];
			node2=p[node2][i];
		}
	}
	if(node1!=node2) ans=max(ans,max(cost[node1][0],cost[node2][0]));
	return ans;
}
void init()
{
	memset(p,-1,sizeof(p));
	memset(cost,0,sizeof(cost));
	memset(visit,0,sizeof(visit));
	memset(father,-1,sizeof(father));
	bit=0;
	while((1<<bit)<=n) bit++;
	for(int i=0;i<=n-1;i++)
		G[i].clear();
	return;
}
void input()
{
	for(int i=0;i<=m-1;i++)
	{
		cin>>edge[i].from>>edge[i].to>>edge[i].dan;
		edge[i].from--;
		edge[i].to--;
	}
	return;
}
int main()
{
	int c=0;
	while(cin>>n>>m)
	{
		if(c++) cout<<endl;
		init();
		input();
		kruskal();
		for(int i=0;i<=n-1;i++)
		{//没仔细看题,不知道是不是有不连通的情况- -
			if(!visit[i])
			{
				visit[i]=1;
				dfs(i,0,-1);
			}
		}
		for(int i=0;i<=m-1;i++)
		{
			if(edge[i].v&&p[edge[i].from][0]==edge[i].to) cost[edge[i].from][0]=edge[i].dan;
			if(edge[i].v&&p[edge[i].to][0]==edge[i].from) cost[edge[i].to][0]=edge[i].dan;
		}
		find_ancestor(); 
		int q,s,t;
		cin>>q;
		while(q--)
		{
			cin>>s>>t;
			if(fa[s-1]<fa[t-1])
				cout<<solve(t-1,s-1)<<endl;
			else cout<<solve(s-1,t-1)<<endl;
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值