• 【并查集】wikioi1001舒适的路线


    1001 舒适的路线

    Z小镇是一个景色宜人的地方,吸引来自各地的观光客来此旅游观光。
    Z小镇附近共有
    N(1<N≤500)个景点(编 号为1,2,3,…,N),这些景点被M(0<M≤5000)条道路连接着,所有道路都是双向的,两个景点之间可能有多条道路。也许是为了保护该地 的旅游资源,Z小镇有个奇怪的规定,就是对于一条给定的公路Ri,任何在该公路上行驶的车辆速度必须为Vi。频繁的改变速度使得游客们很不舒服,因此大家 从一个景点前往另一个景点的时候,都希望选择行使过程中最大速度和最小速度的比尽可能小的路线,也就是所谓最舒适的路线。

    第一行包含两个正整数,N和M。
    接下来的M行每行包含三个正整数:x,y和v(1≤x,y≤N,0 最后一行包含两个正整数s,t,表示想知道从景点s到景点t最大最小速度比最小的路径。s和t不可能相同。

    如果景点s到景点t没有路径,输出“IMPOSSIBLE”。否则输出一个数,表示最小的速度比。如果需要,输出一个既约分数。

    样例1
    4 2
    1 2 1
    3 4 2
    1 4

    样例2
    3 3
    1 2 10
    1 2 5
    2 3 8
    1 3

    样例3
    3 2
    1 2 2
    2 3 4
    1 3

    样例1
    IMPOSSIBLE

    样例2
    5/4

    样例3
    2

    N(1<N≤500)

    M(0<M≤5000)

    Vi在int范围内

    解法

          这其实是一个暴力,之所以说是并查集是用并查集来判断2个边是不是连通的。。

          我写了6个版本才过的。。。。

         伪代码:

          先按速度排序

          然后枚举for(i=1;i<=m;i++)作为第一条边(也就是最大的边)

          {

                for (j=i;j<=m;j++) 

                判断起点和终点是否在同一个并查集内(是否相连)如果是则进行最优解比较

          }

    反省

         1.一定要调用所有写了的有用的函数。。冒泡忘记调用了跪了

         2.不需要单独处理最大边(i那条边)而将j从i+1开始处理,可以直接用j从i开始处理

         3.并查集只要判断2个点是否相连即可,也就是说只要祖宗相同就好,不需要管father是谁,所以只需要father[find(a)]=find(b);将ab相连

    代码

    #include<iostream>
    #include<cstdlib>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    using namespace std;      //头文件 
    
    struct ku
    {
        int from,to,velocity;   
    };
    struct ku a[5005];        //结构体定义 
    
    #define INF 0x7fffffff    //maxlongint定义 
    
    int father[505];
    int use[505];
    int s,t,m,n,ecu1,ecu2;    //变量定义 
    
    //--------------------------------------------------------------
    int gcd(int x1,int x2)    //辗转相除法子程序 
    {
        if (x2!=0) {return gcd(x2,x1%x2);} else {return x1;}
    }
    //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
    void Euclidean()  //辗转相除
    {
        int tmp;
        if (ecu1<ecu2) {tmp=ecu1;ecu1=ecu2;ecu2=tmp;}
        int t=gcd(ecu1,ecu2);
        ecu1=ecu1/t;
        ecu2=ecu2/t;
    }
    //--------------------------------------------------------------
    void bubble()  //冒泡排序 
    {
        int i,j,tmp;
        for (i=1;i<=m-1;i++)
        {
            for (j=i+1;j<=m;j++)
            {
                if (a[i].velocity<a[j].velocity)
                 {tmp=a[i].velocity;a[i].velocity=a[j].velocity;a[j].velocity=tmp;
                  tmp=a[i].from;a[i].from=a[j].from;a[j].from=tmp;
                  tmp=a[i].to;a[i].to=a[j].to;a[j].to=tmp;}
            }
        }
    }
    //--------------------------------------------------------------
    int find(int x){return x==father[x]?x:father[x]=find(father[x]);}  //找祖宗,路径压缩 
    //--------------------------------------------------------------
    int main()
    {
        int i,j,anshave,k;
        double best;
            
        cin>>n>>m;
        for (int i=1;i<=m;i++)
             {cin>>a[i].from>>a[i].to>>a[i].velocity;}
        bubble(); 
        cin>>s>>t;//读入 
        //cout<<"+++++++++++++++++"<<endl;
        for (i=1;i<=m;i++)
        cout<<a[i].from<<' '<<a[i].to<<' '<<a[i].velocity<<endl;
        //cout<<"+++++++++++++++++"<<endl;
        //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  
        anshave=0;//判断是否有解 
        best=INF; //最优解 
        for (i=1;i<=m;i++)  //枚举第一条线段 
        {
            for (k=1;k<=n;k++) father[k]=k; //清空父亲  
            for (j=i;j<=m;j++)  //插入线段(第一条无需特殊处理) 
            {
                father[find(a[j].from)]=find(a[j].to);
                if (find(s)==find(t))   //判断是否得到解 
                  {
                   int p1=a[i].velocity;int p2=a[j].velocity;
                   if (p1<p2){ int tmp=p1;p1=p2;p2=tmp;}
                   if ((double(p1)/double(p2))<best)  //判断是否得到更优解 
                   {    
                     best=(double(p1)/double(p2));
                     ecu1=p1;ecu2=p2;
                   }
                   anshave=1;
                  }
            }
            
        }
        //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -        
        if (anshave==1)  //有解时的输出 
         { 
            Euclidean();
            if (ecu1==0) {cout<<'0'<<endl;return 0;}
            if (ecu2==1) {cout<<ecu1<<endl;return 0;}
            if (ecu1==ecu2) {cout<<'1'<<endl;return 0;}
            cout<<ecu1<<'/'<<ecu2<<endl;
         }
        else  //无解时的输出 
         {
            cout<<"IMPOSSIBLE";
         }
        return 0;
    }

    评测结果

        

         

    题目用户运行结果得分详情总耗时内存占用语言代码提交时间
    1001 舒适的路线 seekdreamer 测试通过 Accepted
    100
    » 1151ms 1736kb C++ 1832B 2014/06/22 19:48:55

    凤巢(Xeon 2.26GHz 1.5G)

    数据时间空间结果
    comf0.in 0ms 1736kB 正确
    comf1.in 4ms 1736kB 正确
    comf2.in 405ms 1736kB 正确
    comf3.in 353ms 1736kB 正确
    comf4.in 389ms 1736kB 正确
     

    模板

          1.并查集搜索祖宗+路径压缩:int find(int x){return x==father[x]?x:father[x]=find(father[x]);}

          2.求最大公因数:(1)int gcd(int a,int b) { if (b!=0) {return gcd(b,a%b);} else {return a;} }

                                (2)while (b!=0) {int tmp=a;a=b;b=tmp%a;}      ans=a;

          3.约分:(约分+输出)(暂时只支持正数)

        gcd=ta与tb的最大公因数
        ta/=gcd;tb/=gcd;
        if (ta==0) {cout<<'0'<<endl;return 0;}
        if (tb==1) {cout<<ta<<endl;return 0;}
        if (ta==tb) {cout<<'1'<<endl;return 0;}
        cout<<ta<<'/'<<tb<<endl;

     鸣谢与数据

    鸣谢给我数据的吴桐。。最后上三组样例数据(不是wikioi评测的数据。。是我自己做的)

    test1:http://www.cnblogs.com/seekdreamer/articles/3803071.html

    test2:http://www.cnblogs.com/seekdreamer/articles/3803076.html

    test3:test3.in

              2 1

              2 1 6

              1 2

              test3.out :1

    noip忘记取模的痛
  • 相关阅读:
    【more effective c++读书笔记】【第6章】杂项讨论
    【more effective c++读书笔记】【第5章】技术(7)——让函数根据一个以上的对象类型来决定如何虚化(2)
    【more effective c++读书笔记】【第5章】技术(7)——让函数根据一个以上的对象类型来决定如何虚化(1)
    【more effective c++读书笔记】【第5章】技术(6)——Proxy classes(代理类)
    【more effective c++读书笔记】【第5章】技术(5)——Reference counting(引用计数)(2)
    【more effective c++读书笔记】【第5章】技术(5)——Reference counting(引用计数)(1)
    【more effective c++读书笔记】【第5章】技术(4)——Smart Pointers(智能指针)
    【more effective c++读书笔记】【第5章】技术(3)——要求(或禁止)对象产生于heap之中
    【more effective c++读书笔记】【第5章】技术(2)——限制某个class所能产生的对象数量
    【more effective c++读书笔记】【第5章】技术(1)——将constructor和non-member functions虚化
  • 原文地址:https://www.cnblogs.com/seekdreamer/p/3803068.html
Copyright © 2020-2023  润新知