[luogu]P2502 [HAOI2006]旅行

原题链接:P2502 [HAOI2006]旅行

题意

找到一条$s$到$t$的路径,使得路径上最大边权和最小边权的比值最小。

求这个最小值。

分析

一开始的思路是从大的开始加边,一直加到刚好连通位置,然后dfs求出最小比值。

但是很容易证明算法是错的。

正解是:从大到小钦定这个最大边权,然后往小边权加边,直到刚好连通。

由于加入小的边权之后刚好连通,易证明小边权必定在这条路径上。

但是大的边权不一定在路径上啊?

没关系,我们反正要倒叙枚举,易证如果这个最大边权不在路径上的话,后面肯定能找到一个更小的比值。

这样子,我们只需要每次求出最大边权和最小边权,然后记录比值最小的那一组就可以了。

 

注意输出格式!

 

代码

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N=509,M=5009;
 4 struct Edge{
 5     int u,v,w;
 6 }g[M];
 7 int read(){
 8     char c;int num,f=1;
 9     while(c=getchar(),!isdigit(c))if(c=='-')f=-1;num=c-'0';
10     while(c=getchar(), isdigit(c))num=num*10+c-'0';
11     return f*num;
12 }
13 int n,m,s,t,pre[N];
14 int Maxn=-1,Minn=(1<<31)-1;
15 bool cmp(Edge a,Edge b){return a.w<b.w;}
16 int fid(int x){return (x==pre[x])?x:(pre[x]=fid(pre[x]));}
17 int gcd(int a,int b){return (b==0)?a:gcd(b,a%b);}
18 int main()
19 {
20     n=read();m=read();
21     for(int i=1;i<=m;i++){
22         g[i].u=read();
23         g[i].v=read();
24         g[i].w=read();
25     }
26     sort(g+1,g+1+m,cmp);
27     s=read();t=read();
28     for(int i=m;i>0;i--){
29         for(int j=1;j<=n;j++)pre[j]=j;
30         int j=i;
31         for(;j>0;j--){
32             if(fid(g[j].u)!=fid(g[j].v))
33                 pre[fid(g[j].u)]=fid(g[j].v);
34             if(fid(s)==fid(t))break;
35         }
36         if(fid(s)!=fid(t))break;
37         if(Maxn==-1||1.0*g[i].w/g[j].w<1.0*Maxn/Minn){
38             Maxn=g[i].w;
39             Minn=g[j].w;
40         }
41     }
42     if(Maxn==-1){
43         printf("IMPOSSIBLE\n");
44         return 0;
45     }
46     int d=gcd(Maxn,Minn);
47     Maxn/=d;Minn/=d;
48     printf("%d",Maxn);
49     if(Minn!=1)printf("/%d",Minn);
50     printf("\n");
51     return 0;
52 }
View Code

 

posted @ 2018-12-02 17:14  _onglu  阅读(139)  评论(0编辑  收藏  举报