NYOJ 1248 海岛争霸 河南省赛真题 Floyd 或者 并查集

海岛争霸

时间限制: 1000 ms  |  内存限制: 65535 KB
难度: 3
描述
神秘的海洋,惊险的探险之路,打捞海底宝藏,激烈的海战,海盗劫富等等。加勒比海盗,你知道吧?杰克船长驾驶着自己的的战船黑珍珠1号要征服各个海岛的海盜,最后成为海盗王。 这是一个由海洋、岛屿和海盗组成的危险世界。杰克船长准备从自己所占领的岛屿A开始征程,逐个去占领每一个岛屿。面对危险重重的海洋与诡谲的对手,如何凭借智慧与运气,建立起一个强大的海盗帝国。
杰克船长手头有一张整个海域的海图,上面详细地记录了各个海屿的位置,以及海屿之间的通航路线。但他发现,有的航海路线太危险了,杰克船长的战船很难直接通过,他必须想方设法绕道航行;还有的岛屿根本到达不了。
杰克船长现在想把航行的危险程度降到最小。具体地来说,就是杰克船长提出若干个询问,他想知道从岛屿A 到岛屿B 有没有行驶航线,若有的话,所经过的航线,危险程度最小可能是多少。
输入
第1行: N M 表示有N个岛屿,M条直航路线
第2~M+1行: A B V 表示从岛屿A到岛屿B的航海路线的危险程度值为V。
接下面一行 : Q 表示询问的次数。
之后有Q个行: A B 表示询问从岛屿A 到岛屿B 所经过的航线,危险程度最小值
1<N≤100 0<M≤500 1≤ Q≤20 0 < V≤1000,
所有数据都是正整数。输入数据之间有一个空格。
输出
对于每个询问,输出占一行,一个整数,表示从岛屿A 到岛屿B 所经过的航线,危险程度最小值;若从岛屿A 无法到达岛屿B,则输出-1。
样例输入
10 8
1 2 5
1 3 2
2 3 11
2 4 6
2 4 4
6 7 10
6 10 5
10 7 2
5
2 3
1 4
3 7
6 7
8 3
样例输出
5
5
-1
5
-1

Floyd

 
#include<stdio.h>
#define MAX 0x3f3f3f
int max(int x,int y)
{
	return x>y?x:y;
}
int min(int x,int y)
{
	return x<y?x:y;
}
int main()
{
	int n,m,u,v,x,map[110][110],i,j,k,q,a,b;
	scanf("%d%d",&n,&m);
	for(i=0;i<=n;i++)
		for(j=0;j<=n;j++)
		{
			if(i==j)
				map[i][j]=0;
			else
				map[i][j]=MAX;
		}
	for(i=0;i<m;i++)
	{
		scanf("%d%d%d",&u,&v,&x);
		if(x<map[u][v])
		{
			map[u][v]=x;
			map[v][u]=x;
		}
	}
	for(k=1;k<=n;k++)		
		for(i=1;i<=n;i++)
			for(j=1;j<=n;j++)
			{
				if(map[i][k]!=MAX&&map[k][j]!=MAX)
				{
					int big=max(map[i][k],map[k][j]);
					map[i][j]=min(map[i][j],big);
				}
			}
	scanf("%d",&q);
	for(i=0;i<q;i++)
	{
		scanf("%d%d",&a,&b);
		if(map[a][b]==MAX)
		 printf("%d\n",-1);
		else
		 printf("%d\n",map[a][b]);
	}
	return 0;
}
        

并查集

#include<stdio.h>
#include<stdlib.h>
int n,m,b[1001],max;
//bool flag;
struct edge{
	int u,v,w;
}a[2000];
int cmp(const void *a,const void *b){
	return (*(edge*)a).w > (*(edge*)b).w ?1:-1;
}
void ufset(){//初始化
	for(int i=0;i<n;i++)
	b[i]=-1;
}
int find(int x){//查找并返回x的根结点 
	int i;
	for(i=x;b[i]>=0;i=b[i]);
	while(i!=x){//压缩路径 
		int temp=b[x];//交换
		b[x]=i;
		x=temp;
	}
	return i;
}
void Union(int R1,int R2){//不同集合的r1,r2合并
	int r1=find(R1), r2=find(R2);//r1为R1的根结点 ,r2为R2的根结点
	if(r1<r2){
		b[r1]=b[r1]+b[r2]; b[r2]=r1;//b[r1]<b[r2],因为是负数
	}
	else {
		b[r2]=b[r1]+b[r2]; b[r1]=r2;
	}
}
void juden(int c,int d){
	int u,v;
	max=-1;
	ufset();
	for(int i=0;i<m;i++){
		u=a[i].u; v=a[i].v;
		if(find(u)!=find(v)){
			Union(u,v);
			if(find(c)==find(d)){
             if(max<a[i].w)max=a[i].w;		
	        } 
		} 
		if(max!=-1) break;
	}
	printf("%d\n",max);
}	
int main(){
	int i;
	scanf("%d%d",&n,&m);
	   int k,c,d;
		for(i=0;i<m;i++)
		scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
		qsort(a,m,sizeof(a[0]),cmp);
		//printf("1\n");
		scanf("%d",&k);
		while(k--){
		scanf("%d%d",&c,&d);
		juden(c,d);
		}
	return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值