• hdu 1875 畅通工程再续


     最小生成树的入门题,和普通裸题有些区别,需要做出一点修改

    题目是要求两个岛的直接连线要大于等于10小于等于1000而不是说任意两个岛的路径和都是要满足这个条件,否则的话,要满足任意两个岛的路径和满足这个条件还是比较麻烦的

    显然这道题用prim算法实现才好,因为最多有n*(n-1)/2条边用kruskal算法不好

    在prim模板中要修改两个地方几个,一个是初始化

     

      for(i=1; i<=n; i++)

        {

            adj[i]=1;

            if(g[1][i]>=MIN) lowcoat[i]=g[1][i];

            else             lowcoat[i]=INF;

        }

        lowcoat[1]=0;

     

    原本是直接lowcoat[i]=g[1][i]; 的。但是知道在prim算法中我们是不断更新lowcoat[i]使它的值不断变小的,所以lowcoat[i]只会越来越小,如果lowcoat[i]的值在初始化过程中就已经小于10,那么最后的构建结果中某条路径的长度一定小于10.

    另外一个不同于模板的地方是

    for(i=1; i<=n; i++)

                if(lowcoat[i] && lowcoat[i]>g[k][i] && g[k][i]>=MIN)

                {

                    lowcoat[i]=g[k][i];

                    adj[i]=k;

                }

     

    同样地,是为了避免在更新lowcoat[i]的时候使它的值小于10或大于1000,

     

    for(sum=0,i=2; i<=n; i++)

        {

            if(g[i][adj[i]] < MIN || g[i][adj[i]]> MAX)  { sum=-1; break;}

            sum+=g[i][adj[i]];

        }

    这个就是最后的判断,判断所有n-1条连线,然后看每条连线是否满足条件,只要有一条连线不满足条件,就说明构建失败

     

    而有些小细节还是可以修改一下的,更新部分可以改为

            for(i=1; i<=n; i++)
                if(lowcoat[i] && lowcoat[i]>g[k][i] && g[k][i]>=MIN)
                {
                    lowcoat[i]=g[k][i];
                    adj[i]=k;
                }

    最后判断是否构建成功部分可以改为

    for(sum=0,i=2; i<=n; i++)
        {
            if(g[i][adj[i]]> MAX)  { sum=-1; break;}
            sum+=g[i][adj[i]];
        }

     

     

    #include <stdio.h>
    #include <string.h>
    #include <math.h>
    #define N 110
    #define MIN 10
    #define MAX 1000
    #define INF 982382334
    int n;
    int x[N],y[N];
    double g[N][N];
    
    double dis(int i , int j)
    { return sqrt( 1.0*((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])) ); }
    
    void input()
    {
        int i,j;
        scanf("%d",&n);
        for(i=1; i<=n; i++)
            scanf("%d%d",&x[i],&y[i]);
    
        for(i=1; i<=n; i++)
            for(j=1 ;j<=n; j++)
                g[i][j]=g[j][i]=dis(i,j);
        return ;
    }
    void print_graph()
    {
        int i,j;
        for(i=1; i<=n; i++)
        {
            for(j=1; j<=n; j++)
                printf("%.1lf ",g[i][j]);
            printf("\n");
        }
    }
    
    void prim()
    {
        double lowcoat[N],min,sum;
        int adj[N];
        int v,i,j,k;
    
        for(i=1; i<=n; i++)
        {
            adj[i]=1;
            if(g[1][i]>=MIN) lowcoat[i]=g[1][i];
            else             lowcoat[i]=INF;
        }
        lowcoat[1]=0;
    
        for(v=1; v<n; v++)  //还要纳入n-1个点
        {
            min=INF; k=1;
            for(i=1; i<=n; i++)
                if(lowcoat[i] && lowcoat[i]<min)
                { min=lowcoat[i]; k=i;}
    
            lowcoat[k]=0;
    
            for(i=1; i<=n; i++)
                if(lowcoat[i] && lowcoat[i]>g[k][i] && g[k][i]>=MIN)
                {
                    lowcoat[i]=g[k][i];
                    adj[i]=k;
                }
        }
    
        for(sum=0,i=2; i<=n; i++)
        { 
            if(g[i][adj[i]] < MIN || g[i][adj[i]]> MAX)  { sum=-1; break;}
            sum+=g[i][adj[i]];
        }
        if(sum==-1)  printf("oh!\n");
        else
        {
            sum*=100;
            printf("%.1lf\n",sum);
        }
        return ;
    }
    
    int main()
    {
        int T;
        double ans;
        scanf("%d",&T);
        while(T--)
        {
            input();
    //        print_graph();
            prim();
        }
        return 0;
    }

     

  • 相关阅读:
    cxVerticalGrid赋值是实时更新
    cxGrid类似pagecontrol的效果
    cxgrid属性说明,每次用的时候费时费力查找。
    做一个平均数,合计数的sql查询
    FDMemTable 提示操作速度尤其是循环
    手机号码验证
    取字符串长度
    DELPHI 获取本月 的第一天 和 最后一天
    SQL Server 断开某个数据库所有连接(还原的时候需要)转自用保留
    元宇宙六大核心技术
  • 原文地址:https://www.cnblogs.com/scau20110726/p/2729776.html
Copyright © 2020-2023  润新知