【并查集】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忘记取模的痛
原文地址:https://www.cnblogs.com/seekdreamer/p/3803068.html