codevs 1001 舒适的路线 并查集

来源:互联网 发布:第一批网络主播黑名单 编辑:程序博客网 时间:2024/05/16 10:59

题目:
http://codevs.cn/problem/1001/

n^2logn,这个题挺好的,有点难想;
主要还是自己不熟;

开始思路有点瑕疵,以为只能枚举存在起点或终点的边,再枚举比他边权小的边,其实这是不对的,因为除了存在起点和终点的边,其他的边均可作为连接终点和起点的中介来更新答案;

思路:
将边按边权从小到大排序;
枚举每一条边,边权记为max;
再枚举比他边权小的边,加入一个集合,同时更新min,直到起点和终点到一个集合内,更新答案;

总结:
1.当输出inf时,说明限制太小,或思路不对,及时修改;
2.若是双向边,很可能与并查集有关,多往这里想;

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>using namespace std;typedef long double dou;const int MAXN=300001,inf=2147483647;int tot,fa[MAXN],ss[MAXN];int n,m,sx,sy,cx=inf,cy=1;struct hh{    int from,to,cost;}ma[MAXN];int find(int x){    int r=x,t;    while(r!=fa[r]) r=fa[r];    while(x!=r) t=fa[x],fa[x]=r,x=t;    return r;}bool cmp(hh a,hh b){    return a.cost < b.cost;}int gcd(int a,int b){    if(a%b==0) return b;    else return gcd(b,a%b);}void solve(){    int x,y,z,fx,fy;    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++) fa[i]=i;    for(int i=1;i<=m;i++)    {        scanf("%d%d%d",&x,&y,&z);        fx=find(x),fy=find(y);        ma[i]=(hh){x,y,z};        if(fx!=fy) fa[fx]=fy;    }    scanf("%d%d",&sx,&sy);    if(find(sx)!=find(sy)) { printf("IMPOSSIBLE\n");return;}    sort(ma+1,ma+m+1,cmp);    for(int k=1;k<=m;k++)    {        int maxx=ma[k].cost,minn=214748369;        for(int i=1;i<=n;i++) fa[i]=i;        for(int i=k;i>=1;i--)        {            int fx=find(ma[i].from),fy=find(ma[i].to);            if(fx!=fy) fa[fx]=fy;            minn=min(minn,ma[i].cost);            if(find(sx)==find(sy))            {                if((((dou)maxx)/((dou)minn)) <= (((dou)cx)/((dou)cy)))                 cx=maxx,cy=minn;                break;            }        }    }    if(cx%cy==0) cout<<cx/cy;    else     {        int t=gcd(cx,cy);        cout<<cx/t<<"/"<<cy/t<<endl;    }}int main(){    solve();    return 0;}
原创粉丝点击