BZOJ1050 [HAOI2006]旅行

本文介绍了一种使用并查集解决最简分数路径问题的方法,通过将边按权值排序,并逐步添加边来判断两节点是否连通,从而找到最简分数路径。

其实这道题根本不用最短路算法...

我们可以就把边从小到大排序,那么只需要枚举大小两个端点,把中间的边都加进去判断联通性即可.

判断联通性显然用的是并查集.

#include <cstdio>
#include <algorithm>
struct DJSET{
	struct{
		int fa,rk;
	} p[505];
	int find(int k){ return p[k].fa?p[k].fa=find(p[k].fa):k; }
	inline void merge(int a,int b){
		a=find(a),b=find(b);
		if(a==b) return;
		if(p[a].rk<p[b].rk) std::swap(a,b);
		p[b].fa=a;
		if(p[a].rk==p[b].rk) ++p[a].rk;
	}
} set[5005];
struct eg{
	int f,t,l;
	inline void read(){
		scanf("%d%d%d",&f,&t,&l);
	}
} Es[5005];
int gcd(int a,int b){
	if(a) return gcd(b%a,a);
	return b;
}
bool cmp(const eg& a,const eg& b){
	return a.l<b.l;
}
int m,n,i,j,s,t;
int FA,FB,FC,FA1,FB1,FC1;
inline void reduce(){
	FC=gcd(FA,FB);
	FA/=FC,FB/=FC;
}
int main(){
	scanf("%d%d",&n,&m);
	for(i=0;i<m;++i) Es[i].read();
	std::sort(Es,Es+m,cmp);
	scanf("%d%d",&s,&t);
	FA1=1000;
	for(i=0;i<m;++i){
		for(j=i;j<m;++j){
			set[i].merge(Es[j].f,Es[j].t);
			if(set[i].find(s)==set[i].find(t)){
				FA=Es[j].l,FB=Es[i].l;
				reduce();
				if(FA*FB1<FB*FA1){
					FA1=FA;
					FB1=FB;
				}
				break;
			}
		}
	}
	if(FB1==0) printf("IMPOSSIBLE"); else{
		if(FB1==1) printf("%d\n",FA1); else printf("%d/%d\n",FA1,FB1);
	}
	return 0;
}

其实有个小优化:当所有边都加入而不联通时直接退出IMPOSSIBLE.

然后哎唷我擦快了不少...

#include <cstdio>
#include <algorithm>
struct DJSET{
	struct{
		int fa,rk;
	} p[505];
	int find(int k){ return p[k].fa?p[k].fa=find(p[k].fa):k; }
	inline void merge(int a,int b){
		a=find(a),b=find(b);
		if(a==b) return;
		if(p[a].rk<p[b].rk) std::swap(a,b);
		p[b].fa=a;
		if(p[a].rk==p[b].rk) ++p[a].rk;
	}
} set[5005];
struct eg{
	int f,t,l;
	inline void read(){
		scanf("%d%d%d",&f,&t,&l);
	}
} Es[5005];
int gcd(int a,int b){
	if(a) return gcd(b%a,a);
	return b;
}
bool cmp(const eg& a,const eg& b){
	return a.l<b.l;
}
int m,n,i,j,s,t;
int FA,FB,FC,FA1,FB1,FC1;
inline void reduce(){
	FC=gcd(FA,FB);
	FA/=FC,FB/=FC;
}
int main(){
	scanf("%d%d",&n,&m);
	for(i=0;i<m;++i) Es[i].read();
	std::sort(Es,Es+m,cmp);
	scanf("%d%d",&s,&t);
	FA1=1000;
	for(i=0;i<m;++i){
		for(j=i;j<m;++j){
			set[i].merge(Es[j].f,Es[j].t);
			if(set[i].find(s)==set[i].find(t)){
				FA=Es[j].l,FB=Es[i].l;
				reduce();
				if(FA*FB1<FB*FA1){
					FA1=FA;
					FB1=FB;
				}
				break;
			}
		}
		if(FB1==0){
			printf("IMPOSSIBLE\n");
			return 0;
		}
	}
	if(FB1==1) printf("%d\n",FA1); else printf("%d/%d\n",FA1,FB1);
	return 0;
}

由于空间够大我还偷了个懒没有每次memset一遍...然后就出现了奇异的景象:

Submit1737
User(Submit)735
User(Solved)702
AC871
WA460
TLE196
MLE3
OLE6
RE143
CE58
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
AC[50%]
 
WA[26%]
 
TLE[11%]
 
MLE[0%]
 
OLE[0%]
 
RE[8%]
 
CE[3%]
No.RunIDUserMemoryTimeLanguageCode_LengthSubmit_Time
241546203absi20111468 KB1076 MSC++2608 B2014-02-14 16:51:06
242695809zhengly1231824 KB1076 MSC++1730 B2014-07-15 14:58:06
243473121sth1997864 KB1088 MSC++1321 B2013-08-29 10:59:59
244967344(2)tmzbot20616 KB1116 MSC++1311 B2015-05-08 14:26:09
245312288Maigo1352 KB1144 MSC++1060 B2012-10-06 16:16:30
246234103Oct_Gap201372 KB1152 MSPascal4710 B2012-03-27 16:40:05
247786906Nano_Ape1480 KB1152 MSC++1705 B2014-11-26 14:35:22
2486697(2)Sachs700 KB1153 MSPascal2155 B2009-09-09 18:39:30
249221303TSZWL368 KB1156 MSPascal4662 B2012-03-10 16:07:32
250244488(2)bill125368 KB1156 MSPascal4662 B2012-04-16 23:08:22
251214563(2)sbsbsbsb368 KB1160 MSPascal4670 B2012-02-28 21:34:20
252197945This_poet1396 KB1168 MSC++1564 B2012-02-01 17:13:54
25367605nathenqian268 KB1183 MSC++1737 B2010-12-11 14:49:13
25468313cfttcc860 KB1183 MSPascal1751 B2010-12-14 13:33:07
25575681crfish600 KB1184 MSPascal1662 B2011-02-25 23:25:16
25629182wu3412790620 KB1184 MSPascal1381 B2010-06-11 17:00:14
257661385RealCS1396 KB1188 MSC++1560 B2014-05-30 15:37:42
25812275thegreysky320 KB1199 MSC++1523 B2010-03-09 22:25:46
2596500zr_1234684 KB1201 MSPascal1957 B2009-09-01 18:26:15
260460098Ruchiose1332 KB1212 MSC++2924 B2013-08-02 17:20:09
[TOP]  [STATUS]  [PREV]  [NEXT]

2W多KB的那个SB就是我.

转载于:https://www.cnblogs.com/tmzbot/p/4487593.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值