• hdu 4463 Outlets(最小生成树)


    题意:n个点修路,要求总长度最小,但是有两个点p、q必须相连

    思路:完全图,prim算法的效率取决于节点数,适用于稠密图。用prim求解。

    p、q间距离设为0即可,最后输出时加上p、q间的距离

    prim算法:

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    using namespace std;
    
    #define INF 15000//计算得最长值
    #define MAXN 128
    bool vis[MAXN];
    double lowc[MAXN];
    
    struct Point{
        double x,y;
    }p[MAXN];
    
    double dis(Point a,Point b){
        return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
    }
    
    double prim(double cost[][MAXN],int n){//标号从0开始
        double ans=0,minc;
        int i,j,p;
        memset(vis,false,sizeof(vis));
        vis[0]=true;
        for(i=1;i<n;++i)lowc[i]=cost[0][i];
        for(i=1;i<n;++i){
            minc=INF;
            p=-1;
            for(j=0;j<n;++j)
                if(!vis[j]&&lowc[j]<minc){
                    minc=lowc[j];
                    p=j;
                }
            if(minc==INF)return -1;//原图不连通
            ans+=minc;
            vis[p]=true;
            for(j=0;j<n;++j)
                if(!vis[j]&&cost[p][j]<lowc[j])
                    lowc[j]=cost[p][j];
        }
        return ans;
    }
    
    int main(){
        int n,m,a,b,i,j;
        double cost[MAXN][MAXN],w;
        while(~scanf("%d",&n)&&n){
            //m=n*(n-1)/2;//m边条数
            scanf("%d%d",&a,&b);
            --a;--b;
            for(i=0;i<n;++i)
                scanf("%lf%lf",&p[i].x,&p[i].y);
    
            for(i=0;i<n;++i)
                for(j=i+1;j<n;++j){
                    w=dis(p[i],p[j]);
                    if((i==a&&j==b)||(j==a&&i==b))w=0;
                    cost[i][j]=cost[j][i]=w;
                }
            printf("%.2f
    ",prim(cost,n)+dis(p[a],p[b]));
        }
        return 0;
    }
    View Code

    kruskal算法的效率取决于边数,适用于稀疏图。

    边数为50*50,也不是很多,也可用kruskal算法:

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<math.h>
    using namespace std;
    
    #define MAXN 110//最大点数
    #define MAXM 10000//最大边数
    int F[MAXN];//并查集使用
    
    struct Point{
        double x,y;
    }p[MAXN];
    
    struct Edge{
        int u,v;
        double w;
    }edge[MAXM];//存储边的信息,包括起点/终点/权值
    int tol;//边数,加边前赋值为0
    
    double dis(Point a,Point b){
        return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
    }
    
    void addedge(int u,int v,double w){
        edge[tol].u=u;
        edge[tol].v=v;
        edge[tol++].w=w;
    }
    
    //排序函数,将边按照权值从小到大排序
    bool cmp(Edge a,Edge b){
        return a.w<b.w;
    }
    
    int find(int x){
        if(F[x]==-1)return x;
        return F[x]=find(F[x]);
    }
    
    //传入点数,返回最小生成树的权值,如果不连通返回-1
    double kruskal(int n){
        memset(F,-1,sizeof(F));
        sort(edge,edge+tol,cmp);
        int cnt=0;//计算加入的边数
        int i,u,v,t1,t2;
        double w,ans=0;
        for(i=0;i<tol;++i){
            u=edge[i].u;
            v=edge[i].v;
            w=edge[i].w;
            t1=find(u);
            t2=find(v);
            if(t1!=t2){
                ans+=w;
                F[t1]=t2;
                ++cnt;
            }
            if(cnt==n-1)break;
        }
        if(cnt<n-1)return -1;//不连通
        return ans;
    }
    
    int main(){
        int n,a,b,i,j;
        double w;
        while(~scanf("%d",&n)&&n){
            scanf("%d%d",&a,&b);
            for(i=1;i<=n;++i)
                scanf("%lf%lf",&p[i].x,&p[i].y);
    
            tol=0;
            for(i=1;i<=n;++i)
                for(j=i+1;j<=n;++j){
                    w=dis(p[i],p[j]);
                    if((i==a&&j==b)||(j==a&&i==b))w=0;
                    addedge(i,j,w);
                }
            printf("%.2f
    ",kruskal(n)+dis(p[a],p[b]));
        }
        return 0;
    }
    View Code
  • 相关阅读:
    python 冒泡、二分查找
    pycharm 中按照文档引包方式,引包错误
    开发环境配置
    css,响应鼠标事件,文字变色
    Python 文档学习
    timestamp与timedelta,管理信息系统概念与基础
    中文词频统计
    文件方式实现完整的英文词频统计实例
    组合数据类型练习,英文词频统计实例上
    凯撒密码、GDP格式化输出、99乘法表
  • 原文地址:https://www.cnblogs.com/gongpixin/p/4782294.html
Copyright © 2020-2023  润新知