zoukankan      html  css  js  c++  java
  • USACOCow Tours

    来源:http://ace.delos.com/usacoprob2?a=ecro6SKAJN4&S=cowtour

    看到题目的数据范围就知道这题应该用O(n^3)的算法做了,明显图论中Floyd算法就符合要求。

    算法:

    1.floyd求出任意两点的距离;

    2.对于连通块A和连通块B,添加一条边e(u,v),把A和B联通,新的连通块称为C,则:

              dist[C]=dist[A][u]+dist[B][v]+e(u,v)         //dist[C]表示连通块C的最大距离,dist[A][u]表示连通块A中的点离u点的最远距离

    3.枚举边e(u,v),找出最小的最大距离

    具体的程序如下:

    /*
    ID:ay27272
    PROG:cowtour
    LANG:C++
    */
    
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <math.h>
    using namespace std;
    
    #define MINN 0.0001
    
    struct node{
        int x,y;
        node()
        {
            x=y=0;
        }
        node(int a,int b)
        {
            x=a; y=b;
        }
    };
    
    double a[155][155];
    struct node d[155];
    int n;
    
    double sqrtt(int a,int b)          //求出两点的距离
    {
        double x1=d[a].x-d[b].x;
        double x2=d[a].y-d[b].y;
        return sqrt(x1*x1+x2*x2);
    }
    
    void floyd()
    {
        for (int k=1;k<=n;k++)       //floyd算法模板
            for (int i=1;i<=n;i++)
            if (i!=k)
                for (int j=1;j<=n;j++)
                if (i!=j && k!=j)
                if (a[i][k]>MINN && a[k][j]>MINN &&
                    (a[i][j]-a[i][k]-a[k][j]>MINN || a[i][j]<MINN))
                    a[i][j]=a[i][k]+a[k][j];
    
        for (int i=1;i<=n;i++)       //记录每个点在其连通块中与其它点的最大距离
            for (int j=1;j<=n;j++)
            if (a[i][0]<a[i][j])
                a[i][0]=a[i][j];
    }
    
    int main()
    {
        freopen("cowtour.in","r",stdin);
        freopen("cowtour.out","w",stdout);
        int xx,yy;
        scanf("%d",&n);
        for (int i=1;i<=n;i++)
        {
            scanf("%d%d\n",&xx,&yy);
            d[i]=node(xx,yy);
        }
        char s[200];
        for (int i=1;i<=n;i++)
        {
            gets(s);
            for (int j=0;j<n;j++)
            {
                if (s[j]=='0') a[i][j+1]=a[j+1][i]=0.0;
                else a[i][j+1]=a[j+1][i]=sqrtt(i,j+1);
            }
        }
    
        floyd();
    
        double maxx=10000000.0,k;
        for (int i=1;i<=n;i++)       //枚举边e(i,j)
            for (int j=1;j<=n;j++)
            if (i!=j)
            {
                k=sqrtt(i,j)+a[i][0]+a[j][0];
                if (a[i][j]<MINN && k<maxx)
                maxx=k;
            }
        for (int i=1;i<=n;i++)        //这一步不能省,因为有可能添加边后最大的距离并不在这个新的连通块中
            maxx=max(maxx,a[i][0]);
    
        printf("%.6lf\n",maxx);
        return 0;
    }
  • 相关阅读:
    hdu 4396(spfs/二维最短路)
    hdu 4360(最短路变形)
    hdu 3501(欧拉函数的应用)
    bnu 4359(数位dp)
    用Hermite插值方法估计积分值
    虞旦盛老师 的《数学分析续》课件
    数值积分中的梯形法则
    数值积分中的梯形法则
    辛普森三八律
    利用自然数的标准分解证明可数集合的所有有限子集形成的集合是可数集
  • 原文地址:https://www.cnblogs.com/ay27/p/2800723.html
Copyright © 2011-2022 走看看