UVA 10048 - Audiophobia

版权声明:未经本人同意,禁止转载。 https://blog.csdn.net/qq_34022601/article/details/84642885

题目大意:

C个点,S条边,Q个询问,存在多组数据输入。

无向图边权非负,问两点间路径中边权最大值集合中,输出最大值最小的那条路径的最大值。


解题思路:

1.Floyd的变形:

如果我们把Floyd算法     dis[i][j]=min(dis[i][k]+dis[k]+[j])    变形如下:

i-->k,k-->j 的路径最大值和当前i-->j的路径最大值比较,我们选取最大值小的哪一个,Floyd仍然成立。

                                 dis[i][j]=min(dis[i][j],max(dis[i][k],dis[k][j]))

2.Kruskal的求解:

这道题目我们可以使用最小生成树来解决,只需要我们检查起点和终点在何时连通(并查集)。

因为最小生成树在增长的过程中基于贪心,不断把能加入路径的最短边放入生成树中,当起点终点连通时,一定保证这是一条最大边最小的路径。


代码实现:

1.Floyd的解法:

/*
	Date: 01/12/18 10:01
	Description: 
	Floyd 算法解决 
*/
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
const int INF=1<<29;
struct Node{
	vector <int> adj;
}g[105];
int dis[105][105];
void  Floyd(int c)
{
	for (int k=1;k<=c;k++)
	{
		for (int i=1;i<=c;i++)
		{
			for (int j=1;j<=c;j++)
			{
				dis[i][j]=min(dis[i][j],max(dis[i][k],dis[k][j]));
			}
		}
	} 
}
int main()
{
	int s,c,q,x,y,weight,ts,te,Case=0;
	scanf ("%d%d%d",&c,&s,&q);
	while ((c+s+q))
	{
		for(int i=1;i<=c;i++)
		{
			g[i].adj.clear();
			for (int j=1;j<=c;j++)
			{
				dis[i][j]=INF;
			}
		}
		for (int i=0;i<s;i++)
		{
			scanf ("%d%d%d",&x,&y,&weight);
			if (dis[x][y]==INF)
			{
				dis[y][x]=dis[x][y]=weight;
				g[x].adj.push_back(y);
				g[y].adj.push_back(x);
			}
			if (weight<dis[x][y])
				dis[y][x]=dis[x][y]=weight;
		}
		printf ("Case #%d\n",++Case);
		Floyd(c);
		for (int i=0;i<q;i++)
		{
			scanf("%d %d",&ts,&te);
			if (dis[ts][te]!=INF)
				printf ("%d\n",dis[ts][te]);
			else
				printf ("no path\n");
		}
		scanf ("%d%d%d",&c,&s,&q);
		if (c+s+q)
			printf ("\n");
	}
	return 0;
}

2.Kruskal解法:

 /*
	Date: 01/12/18 10:01
	Description: 
	Kruskal 算法解决 
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF=1<<29;
int u[1005],v[1005],e[1005];//点数组,边数组 
int p[105];//并查集 父数组 
int r[1005];
int Find(int x);
void Union(int r1,int r2);
//重载函数 用于sort 
bool cmp(const int i,const int j)
{
	return e[i]<e[j];
}
void Kruskal(int c,int counter,int ts,int te)
{
	for (int i=1;i<=c;i++)
		p[i]=-1;
	int ans=-1;
	for (int i=0;i<counter;i++)
	{
		int x=u[r[i]];
		int y=v[r[i]];
		int w=e[r[i]];
		if (Find(x)!=Find(y))
		{
			Union(x,y);
			ans=max(w,ans);
		}
		if (Find(ts)==Find(te))
			break;
	}
	if (Find(ts)!=Find(te))
		printf ("no path\n");
	else
		printf ("%d\n",ans);
}
int main()
{
	int s,c,q,x,y,weight,ts,te,Case=0,counter=0;
	scanf ("%d%d%d",&c,&s,&q);
	while ((c+s+q))
	{
		memset(u,0,sizeof(u));
		memset(v,0,sizeof(v));
		memset(e,0,sizeof(e));
		memset(r,0,sizeof(r));
		counter=0;
		for (int i=0;i<s;i++)
		{
			scanf ("%d%d%d",&x,&y,&weight);
			u[counter]=x;
			v[counter]=y;
			e[counter]=weight;
			counter++;
		}
		//Kruskal 排序一次就行 
		for (int i=0;i<counter;i++)
			r[i]=i;
		sort(r,r+counter,cmp);
		printf ("Case #%d\n",++Case);
		for (int i=0;i<q;i++)
		{
			scanf("%d %d",&ts,&te);
			Kruskal(c,counter,ts,te);
		}
		scanf ("%d%d%d",&c,&s,&q);
		if (c+s+q)
			printf ("\n");
	}
	return 0;
}
int Find(int x)
{
	if (p[x]<=0)
		return x;
	else
		return p[x]=Find(p[x]);
}
void Union(int r1,int r2)
{
	r1=Find(r1);
	r2=Find(r2);
	if (r1==r2)
		return ;
	if (p[r1]<p[r2])
		p[r2]=r1;
	else
	{
		if (p[r1]==p[r2])
			p[r2]--;
		p[r1]=r2;
	}
}

猜你喜欢

转载自blog.csdn.net/qq_34022601/article/details/84642885