1050: [HAOI2006]旅行comf
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3335 Solved: 1852
[ Submit][ Status][ Discuss]
Description
给你一个无向图,N(N<=500)个顶点, M(M<=5000)条边,每条边有一个权值Vi(Vi<30000)。给你两个顶点S和T,求一条路径,使得路径上最大边和最小边的比值最小。如果S和T之间没有路径,输出”IMPOSSIBLE”,否则输出这个比值,如果需要,表示成一个既约分数。 备注: 两个顶点之间可能有多条路径。
Input
第一行包含两个正整数,N和M。下来的M行每行包含三个正整数:x,y和v。表示景点x到景点y之间有一条双向公路,车辆必须以速度v在该公路上行驶。最后一行包含两个正整数s,t,表示想知道从景点s到景点t最大最小速度比最小的路径。s和t不可能相同。
1<N<=500,1<=x,y<=N,0<v<30000,0<M<=5000
Output
如果景点s到景点t没有路径,输出“IMPOSSIBLE”。否则输出一个数,表示最小的速度比。
如果需要,输出一个既约分数。
Sample Input
【样例输入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
Sample Output
【样例输出1】
IMPOSSIBLE
【样例输出2】
5/4
【样例输出3】
2
初始化L=1
之后每次循环跑两次Kruskal,
第一次从L开始往上跑直到S和T连接,求出此时的R(刚连接完第R条边就联通)
第二次从R开始往下跑直到S和T连接,求出此时新的'L',这样范围就被缩小到了['L', R],
然后L='L'+1继续上述循环,直到找不到R(从L开始已经不可能再连通了)或者L超出了m的范围结束循环
中间过程中最小的len['L']/len[R]就是答案
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef struct Res
{
int x, y;
int len;
bool operator < (const Res &b) const
{
if(len<b.len)
return 1;
return 0;
}
}Road;
Road s[5005];
int n, m, S, T, ufs[505];
int Gcd(int a, int b)
{
if(b==0)
return a;
return Gcd(b, a%b);
}
int Find(int x)
{
if(ufs[x]==0)
return x;
return ufs[x] = Find(ufs[x]);
}
int Kruskal(int begin, int re)
{
int i, t1, t2;
memset(ufs, 0, sizeof(ufs));
for(i=begin;i<=m&&i>=1;i+=re)
{
t1 = Find(s[i].x);
t2 = Find(s[i].y);
if(t1!=t2)
ufs[t1] = t2;
if(Find(S)==Find(T))
break;
}
if(i>m || i<1)
return -1;
else
return i;
}
int main(void)
{
int i, l, r, x, y, t;
double ans;
while(scanf("%d%d", &n, &m)!=EOF)
{
for(i=1;i<=m;i++)
scanf("%d%d%d", &s[i].x, &s[i].y, &s[i].len);
sort(s+1, s+m+1);
scanf("%d%d", &S, &T);
l = 1;
ans = 100000000;
while(l<=m)
{
r = Kruskal(l, 1);
if(r==-1)
break;
l = Kruskal(r, -1);
if(1.0*s[r].len/s[l].len<ans)
{
ans = 1.0*s[r].len/s[l].len;
x = s[r].len, y = s[l].len;
}
l++;
}
if(ans==100000000)
printf("IMPOSSIBLE\n");
else
{
t = Gcd(x, y);
x /= t, y /= t;
if(y==1)
printf("%d\n", x);
else
printf("%d/%d\n", x, y);
}
}
return 0;
}