计蒜客 简单图论(并查集 + 排序 + 枚举)

来源:互联网 发布:键盘侠网络暴力的危害 编辑:程序博客网 时间:2024/06/16 19:49

一个无向图有n个点和m条边,每条边有权值。两点间的路径权值为这条路径上的最大边权和最小边权的比值。

给定一个起点和一个终点,问从起点到终点的路径中,权值最小的比值是多少。

如果起点和终点无法联通,则输出“No Answer”(结果不带引号)。

输出的比值结果严格保留两位小数。

输入第一行为两个整数,n(1<n≤500)和m(1≤m≤5000)表示图中点的数量和双向边的数量。接下来每行3个整数x,y(1≤x,y≤n),p(0<p<30000)表示点x和点y之间有一条双向边,权值为p。第m+1行为两个整数s,t(1≤s,t≤n, s不等于t),表示起点和终点。

输出仅一个数,表示最小的比值,结果保留两位小数。

样例输入

3 31 2 101 2 52 3 81 3

样例输出

1.25


分析:数据量最大为5000,先排序,再枚举边 + 并查集

AC代码:

#include<cstdio>#include<cstring>using namespace std;#include<algorithm>#define INF 100000000const int maxn=5000+10;int u[maxn],v[maxn],r[maxn],w[maxn];  //r存储边的序号 int pre[500+10];int n,m;bool cmp(int i,int j){return w[i]<w[j];}int find(int x){return x==pre[x]?x:find(pre[x]);}void init(){for(int i=1;i<=n;i++)pre[i]=i;}int main(){while(scanf("%d%d",&n,&m)==2){for(int i=1;i<=m;i++){scanf("%d%d%d",&u[i],&v[i],&w[i]);r[i]=i;}int s,t;scanf("%d%d",&s,&t);        sort(r+1,r+m+1,cmp);        double ans = (double)INF;        int flag=1;                for(int i=1;i<=m;i++){        init();        int j;        for(j=i;j<=m;j++){        int x=u[r[j]],y=v[r[j]];        int fa=find(x),fb=find(y);                if(fa!=fb){        pre[fa]=fb;}if(find(s)==find(t)){break;}}if(find(s)!=find(t)){if(i==1){printf("No Answer\n");flag=0;break ;}else break;}if(ans>(double)w[r[j]]/w[r[i]]){ans=(double)w[r[j]]/w[r[i]];}}if(flag)printf("%.2lf\n",ans);}return 0;}






0 0
原创粉丝点击