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\n",prim(cost,n)+dis(p[a],p[b]));
    }
    return 0;
}

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\n",kruskal(n)+dis(p[a],p[b]));
    }
    return 0;
}

时间: 2024-10-10 01:55:29

hdu 4463 Outlets(最小生成树)的相关文章

hdu 4463 Outlets 最小生成树

#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <stack> #include <set> #include <map> #include <string> #include <ma

HDU 4463 Outlets(一条边固定的最小生成树)

Outlets Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2594    Accepted Submission(s): 1196 Problem Description In China, foreign brand commodities are often much more expensive than abroad. Th

【HDU 4463 Outlets】最小生成树

以(x,y)坐标的形式给出n个点,修建若干条路使得所有点连通(其中有两个给出的特殊点必须相邻),求所有路的总长度的最小值. 因对所修的路的形状没有限制,所以可看成带权无向完全图,边权值为两点间距离.因是稠密图,故用邻接矩阵存储更好(完全图,边数e达到n(n-1)/2). 至此,可将问题抽象为求最小生成树的边权和. 邻接矩阵版Prim算法求最小生成树,时间复杂度为O(n*n).邻接表版prim用堆优化后理论上可达O(elogn),边数组版kruscal理论也为O(elogn),但此题是完全图,e=

HDU 4463 Outlets 【最小生成树】

<题目链接> 题目大意: 给你一些点的坐标,要求你将这些点全部连起来,但是必须要包含某一条特殊的边,问你连起这些点的总最短距离是多少. 解题分析: 因为一定要包含那条边,我们就记录下那条边的边权,然后将那条边边权置为0,再跑一遍最小生成树即可. #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> using namespace std; int n,

HDU 4463: Outlets

http://acm.hdu.edu.cn/showproblem.php?pid=4463 1 #include <iostream> 2 #include <algorithm> 3 #include <cmath> 4 #include <iomanip> 5 //n:= # of vertices 6 using namespace std; 7 const int MAXN = 55; 8 typedef pair<int, int>

HDOJ 4463 Outlets 最小生成树

Prim....似乎没有考虑多点共线也能A..... Outlets Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2565    Accepted Submission(s): 1182 Problem Description In China, foreign brand commodities are often much mo

hdu 4463 Outlets Prim 次小生成树 简单题

Outlets Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2200    Accepted Submission(s): 1028 Problem Description In China, foreign brand commodities are often much more expensive than abroad. T

HDU 4463 Outlets (prime_杭州区域赛水题)

Problem Description In China, foreign brand commodities are often much more expensive than abroad. The main reason is that we Chinese people tend to think foreign things are better and we are willing to pay much for them. The typical example is, on t

hdu 3367 Pseudoforest (最小生成树)

Pseudoforest Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1526    Accepted Submission(s): 580 Problem Description In graph theory, a pseudoforest is an undirected graph in which every connec