P1265 公路修建 最小生成树

  

题目描述

某国有n个城市,它们互相之间没有公路相通,因此交通十分不便。为解决这一“行路难”的问题,政府决定修建公路。修建公路的任务由各城市共同完成。

修建工程分若干轮完成。在每一轮中,每个城市选择一个与它最近的城市,申请修建通往该城市的公路。政府负责审批这些申请以决定是否同意修建。

政府审批的规则如下:

(1)如果两个或以上城市申请修建同一条公路,则让它们共同修建;

(2)如果三个或以上的城市申请修建的公路成环。如下图,A申请修建公路AB,B申请修建公路BC,C申请修建公路CA。则政府将否决其中最短的一条公路的修建申请;

(3)其他情况的申请一律同意。

一轮修建结束后,可能会有若干城市可以通过公路直接或间接相连。这些可以互相:连通的城市即组成“城市联盟”。在下一轮修建中,每个“城市联盟”将被看作一个城市,发挥一个城市的作用。

当所有城市被组合成一个“城市联盟”时,修建工程也就完成了。

你的任务是根据城市的分布和前面讲到的规则,计算出将要修建的公路总长度。

输入输出格式

输入格式:

第一行一个整数n,表示城市的数量。(n≤5000)

以下n行,每行两个整数x和y,表示一个城市的坐标。(-1000000≤x,y≤1000000)

输出格式:

一个实数,四舍五入保留两位小数,表示公路总长。(保证有惟一解)

输入输出样例

输入样例#1: 复制
4
0 0
1 2
-1 2
0 4
输出样例#1: 复制
6.47


难点在 第二条规则 但是显然 这条规则是永远不起作用的

一开始计算所有的距离存在邻接矩阵里面 MLE
#include<bits/stdc++.h>
using namespace std;
//input by bxd
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m)
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s);
#define ll long long
#define pb push_back
#define REP(i,N)  for(int i=0;i<(N);i++)
#define CLR(A,v)  memset(A,v,sizeof A)
#define inf 0x3f3f3f3f
//////////////////////////////////////
const int N = 5000+5;
int f[N];
int find1(int x)
{
    return f[x]==x?x:f[x]=find1(f[x]);
}
struct node
{
    int id,id2;
    double x,y;
    double len;
}s[N],s2[N*N];
int n,m;
int cnt=0;
bool cmp(node a,node b)
{
    return a.len<b.len;
}
int main()
{
    int b;
    RI(b);
    rep(i,1,b)
    {
        scanf("%lf%lf",&s[i].x,&s[i].y);
        s[i].id=i;
        f[i]=i;
    }
    rep(i,1,b)
    rep(j,1,b)
    if(j>i)
    {
        s2[++cnt].id=s[i].id;
        s2[cnt].id2=s[j].id;
        s2[cnt].len=(double)sqrt( (s[i].x-s[j].x)*(s[i].x-s[j].x)+ (s[i].y-s[j].y)*(s[i].y-s[j].y)  );
    }
    sort(s2+1,s2+1+cnt,cmp);
    int x=1;
    double sum=0;
    rep(i,1,cnt)
    {
        int a1=s2[i].id;
        int b1=s2[i].id2;
        a1=find1(a1);b1=find1(b1);
        if(a1==b1)continue;
        x++;
        f[a1]=b1;
        sum+=s2[i].len;
        if(x==b)
        {
            printf("%.2lf",sum);break;
        }
    }
}
View Code

用的时候直接计算即可

发现prim算法打起来更加方便

注意求距离前面要加两个double

#include<bits/stdc++.h>
using namespace std;
//input by bxd
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m)
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s);
#define ll long long
#define pb push_back
#define REP(i,N)  for(int i=0;i<(N);i++)
#define CLR(A,v)  memset(A,v,sizeof A)
#define inf 0x3f3f3f3f
//////////////////////////////////////
const int N = 5000+6;
struct node
{
    int x,y;
}s[N];
double dit(node a,node b)
{
    return sqrt( (double)(a.x-b.x)*(a.x-b.x)+(double)(a.y-b.y)*(a.y-b.y) );
}
int vis[N];
double dis[N];
int main()
{
    int n;
    RI(n);
    rep(i,1,n)
    RII(s[i].x,s[i].y),vis[i]=0,dis[i]=1e8;

    double ans=0;
    dis[1]=0;int u;
    rep(i,1,n)
    {
        double minn=1e8;
        rep(j,1,n)
        if(!vis[j]&&dis[j]<minn)
        minn=dis[u=j];
        ans+=minn;
        vis[u]=1;
        rep(j,1,n)
        {
            double d=dit(s[j],s[u]);
            if(d<dis[j])dis[j]=d;
        }
    }
    printf("%.2lf",ans);
}
View Code






原文地址:https://www.cnblogs.com/bxd123/p/10769934.html