[BZOJ 1050&&HAOI 2006]旅行comf

8 篇文章 0 订阅
5 篇文章 0 订阅

1050: [HAOI2006]旅行comf

Time Limit: 10 Sec   Memory Limit: 162 MB
Submit: 1456   Solved: 715
[ Submit][ Status]

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不可能相同。

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

HINT

【数据范围】

1<  N < = 500

1 < = x, y < = N,0 < v < 30000,x ≠ y

0 < M < =5000

Source


喜闻乐见刷水。。
我也不知道算不算水题,反正一眼题。。。
很明显嘛。。
枚举最短边,二分最长边,每次用DFS判定
复杂度O(nmlogm)
最开始的时候过不去。。被卡常数
然后加了一点小剪枝,就是每次只判定比当前优的。。
然后最开始被卡精度真是爽。。
Code:
const maxn=501;
	  maxm=10001;
var	headlist:array[0..maxn] of longint;
	vis:array[0..maxn] of boolean;
	next,t,w,a:array[0..maxm] of longint;
	map:array[0..maxn,0..maxn] of boolean;
	pppp,time,tmp,left,right,data,re1,re2,now1,mid,l,r,num,j,k,n,m,x,y,z:int64;
	i:longint;
function gcd(a,b:longint):longint;
begin
	if b=0 then exit(a);
	exit(gcd(b,a mod b));
end;
procedure init;
begin
	readln(n,m);
	for i:=1 to n do headlist[i]:=-1;
	for i:=1 to m do
	begin
		readln(x,y,z);
		map[x,y]:=true;
		map[y,x]:=true;
		inc(num);
		a[i]:=z;
		next[num]:=headlist[x];
		headlist[x]:=num;
		t[num]:=y;
		w[num]:=z;
		inc(num);
		next[num]:=headlist[y];
		headlist[y]:=num;
		t[num]:=x;
		w[num]:=z;
	end;
	readln(x,y);
end;
procedure qsort(left,right:longint);
var i,j,mid:longint;
begin
	i:=left; j:=right; mid:=a[(i+j) shr 1];
	repeat
		while a[i]<mid do inc(i);
		while a[j]>mid do dec(j);
		if i<=j then begin
						tmp:=a[i]; a[i]:=a[j]; a[j]:=tmp;
						inc(i); dec(j);
					 end;
	until i>j;
	if j>left  then qsort(left,j);
	if i<right then qsort(i,right);
end;
procedure search(u:longint);
var i:longint;
begin
	vis[u]:=true;
	i:=headlist[u];
	while i<>-1 do
	begin
		if (w[i]<=mid) and (w[i]>=now1) and (not vis[t[i]]) then search(t[i]);
		i:=next[i];
	end;
end;
procedure main;
begin
	init;
	if map[x,y] then begin
						writeln(1);
						halt;
					 end;
	fillchar(vis,sizeof(vis),false);
	now1:=0; mid:=maxlongint;
	search(x);
	if not(vis[y]) then begin
							writeln('IMPOSSIBLE');
							halt;
						end;
	qsort(1,m); re1:=50000; re2:=1;
	for i:=1 to m-1 do
	begin
		now1:=a[i];
		left:=i+1; right:=m;
		repeat
			fillchar(vis,sizeof(vis),false);
			mid:=a[trunc((left+right) shr 1)];
			if mid*re2>now1*re1 then begin
										right:=trunc((left+right) shr 1)-1;
										continue;
									 end;
			search(x);
			if vis[y] then begin
							if mid*re2<now1*re1 then begin
														re1:=mid; re2:=now1;
													end;
							right:=trunc((left+right) shr 1)-1;
						   end
					  else left:=trunc((left+right) shr 1)+1;
		until left>right;
	end;
	data:=gcd(re1,re2);
	re1:=re1 div data;
	re2:=re2 div data;
	if re2<>1 then writeln(re1,'/',re2)
			  else writeln(re1);
end;
begin
	main;
end.


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值