[HAOI2006]旅行

题目:BZOJ1050、codevs1001、洛谷P2502。

题目大意:见BZOJ的题目描述。

解题思路:首先对所有的边按权值排序,然后枚举最小边i,对i~m的所有边,一条一条加进去,当s和t连通时(并查集维护)结束加边并判断最大边和最小边i的比值是否比当前答案较小,如果是则更新。最后得出的即为答案。如果s和t无法连通输出“IMPOSSIBLE”即可。时间复杂度$O(m^2)$。

C++ Code:

 

#include<algorithm>
#include<cstdio>
using namespace std;
int n,m,s,t;
struct Edges{
	int from,to,dis;
	bool operator <(const Edges&rhs)const{return dis<rhs.dis;}
}e[5050];
int fa[505];
int dad(int x){return (x==fa[x])?(x):(fa[x]=dad(fa[x]));}
int gcd(int x,int y){
	if(x%y==0)return y;
	return gcd(y,x%y);
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;++i)
	scanf("%d%d%d",&e[i].from,&e[i].to,&e[i].dis);
	scanf("%d%d",&s,&t);
	sort(e+1,e+1+m);
	int mx=0,mn=2000000000;
	for(int i=1,j;i<=m;++i){
		if(e[i].dis==e[i-1].dis)continue;
		for(j=1;j<=n;++j)fa[j]=j;
		bool flag=false;
		for(j=i;j<=m;++j){
			int a=dad(e[j].from),b=dad(e[j].to);
			if(a!=b)fa[b]=a;
			if(flag=(dad(s)==dad(t)))break;
		}
		if(flag&&(mn>mx||(double)mx/(double)mn>(double)e[j].dis/(double)e[i].dis))mx=e[j].dis,mn=e[i].dis;
	}
	if(mn>mx)puts("IMPOSSIBLE");else
	if(!(mx%mn))printf("%d\n",mx/mn);else{
		int l=gcd(mx,mn);
		printf("%d/%d\n",mx/l,mn/l);
	}
	return 0;
}

 

注意代码第23行的优化。为什么可以这么优化呢?因为这条边与上一条边权值相同,在上一条边作最小边时,这条边已经被加进去过了,所以得到的答案不可能更优,或者是直接连通,比值为1,也不可能更优。所以可以这么优化。

这是在BZOJ中优化前和优化后的对比(上为优化后):

 

 可以看到效果挺好的。

posted @ 2017-08-03 19:48  Mrsrz  阅读(198)  评论(0编辑  收藏  举报