BZOJ1050&&洛谷P2502 [HAOI2006]旅行

这道题一眼看过去,应该是最小生成树没错了,我们可以暴力的枚举一下选哪些边,期望得分40~50

正解是什么呢?我们将边按照边权排序,因为我们要在保证联通的条件下,使得costmax/costmin最小,所以我们要让最小边尽量大的情况下,使得最大边尽量小,如何实现呢?我们发现,因为边权数组已经排好序,所以权值是递增的,所以我们可以选择一些小边权的边不选,看是否还能连通,这样就可以实现在最小边扩大的同时,缩小比值

(这次的代码函数较多,为了更清晰,我开了好多函数,不要喷我的码风,自认为还是比较好看的)

代码

//By AcerMo
#include
#include
#include
#include
#include
#include
using namespace std;
const int M=5500;
int up,down;
int n,fa[M],siz[M],m;
double ans=3005000.0;
struct edge
{
	int fr,to,cost;
}priq[M<<2];
inline int find(int x)
{
	if (x!=fa[x]) return fa[x]=find(fa[x]);
	return x;
}
inline int gcd(int a,int b)
{
	if (!b) return a;
	return gcd(b,a%b);
}
inline int read()
{
	int x=0;char ch=getchar();
	while (ch>'9'||ch<'0') ch=getchar();
	while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return x;
}
inline void unionn(int a,int b)
{
	if (siz[a]now) ans=now,up=priq[i].cost,down=priq[k].cost;
	return ;
}
int main()
{
	n=read();m=read();constt();
	for (int i=1;i<=m;i++)
	{
		priq[i].fr=read();priq[i].to=read();priq[i].cost=read();
		int r1=find(priq[i].fr),r2=find(priq[i].to);
		if (r1!=r2) unionn(r1,r2);	
	}
	int st=read(),ed=read();
	if (find(st)!=find(ed)) return puts("IMPOSSIBLE"),0;
	sort(priq+1,priq+m+1,cmp);
	for (int i=1;i<=m;i++)
	{
		bool flag=0;int e;constt();
		for (int k=i;k<=m;k++)
		{
			int r1=find(priq[k].fr);
			int r2=find(priq[k].to);
			if (r1!=r2) unionn(r1,r2);
			if (find(st)==find(ed)) {e=k;flag=1;break;}
		}
		if (flag) jud(e,i);
	}
	int d=gcd(up,down);
	if (d!=down) printf("%d/%d",up/d,down/d);
	else cout<

你可能感兴趣的:(图论-并查集,图论-最小生成树)