bzoj 1050: [HAOI2006]旅行comf(尺取+最短路)

1050: [HAOI2006]旅行comf

Time Limit: 10 Sec   Memory Limit: 162 MB
Submit: 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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值