您的位置:首页 > 编程语言 > C语言/C++

【OI做题记录】【BZOJ】【HAOI2006】旅行comf

2016-12-11 15:18 323 查看
试题编号:BZOJ2006


给你一个无向图,N(N<=500)个顶点, M(M<=5000)条边,每条边有一个权值Vi(Vi<30000)。给你两个顶点S和T
,求一条路径,使得路径上最大边和最小边的比值最小。如果S和T之间没有路径,输出”IMPOSSIBLE”,否则输出这个比值,如果需要,表示成一个既约分数。
备注: 两个顶点之间可能有多条路径。

输入描述

第一行包含两个正整数,N和M。下来的M行每行包含三个正整数:x,y和v。表示景点x到景点y之间有一条双向
公路,车辆必须以速度v在该公路上行驶。最后一行包含两个正整数s,t,表示想知道从景点s到景点t最大最小速
度比最小的路径。s和t不可能相同。


输出描述

 如果景点s到景点t没有路径,输出“IMPOSSIBLE”。否则输出一个数,表示最小的速度比。如果需要,输出一
个既约分数。

输入样例

【样例输入1】
4 2
1 2 1
3 4 2
1 4
【样例输入2】
3 3
1 2 10
1 2 5
2 3 8
1 3
【样例输入3】
3 2
1 2 2
2 3 4
1 3

输出样例

【样例输出1】
IMPOSSIBLE
【样例输出2】
5/4
【样例输出3】
2

提示

1<N<=500,1
b28a
<=x,y<=N,0<v<30000,0<M<=5000



试题分析

BZOJ的大水题。因为最后要求最大值和最小值的比。所以我们先排序,然后枚举最大边、最小边。在这之中不断加边就可以了。至于怎么判断是否联通:一个并查集搞定。

估计是题目太水,加了一个既约分数的条件。这个也很简单:如果最大边最小边能整除就输出整除的,反之先求最大公约数就好了嘛!
代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
struct qq{
int x,y;
int d;
}a[5005];
int n,m;
int f[505];
int st,ed;
int big=-1.0,sml=999999999.0;double bit=999999999999.0;
bool cmp(qq x,qq y)
{
return x.d>y.d;
}
int findfa(int x)
{
if(f[x]==x)return x;
else f[x]=findfa(f[x]);
return f[x];
}
int gcd(int x,int y)
{
if(y==0)return x;
else return gcd(y,x%y);
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&a[i].x,&a[i].y,&a[i].d);
}
scanf("%d %d",&st,&ed);
sort(a+1,a+m+1,cmp);
bool tf=true;
for(int i=1;i<=m;i++)
{
for(int ii=1;ii<=n;ii++)f[ii]=ii;
for(int j=i;j<=m;j++)
{
if((double)a[i].d/a[j].d>=bit)break;
int x=a[j].x,y=a[j].y;
int fx=findfa(x),fy=findfa(y);
if(fx!=fy)
{
f[fx]=fy;
if(findfa(st)==findfa(ed))
{
big=a[i].d;
sml=a[j].d;
bit=(double)big*1.0/sml;
tf=false;
break;
}
}
}
}
if(tf==true)
{
printf("IMPOSSIBLE\n");
return 0;
}
else
{
if(big%sml==0){printf("%d\n",(int)(big/sml));return 0;}
int soy=gcd(big,sml);
big=big/soy;
sml=sml/soy;
printf("%d/%d",big,sml);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ZSYZlhy bzoj CC++ 并查集