[kuangbin带你飞]专题六 最小生成树 题解 kruskal+prim

版权声明:点个关注(^-^)V https://blog.csdn.net/weixin_41793113/article/details/88951579

专题六 最小生成树 

POJ 1251 Jungle Roads

 

描述


热带岛屿Lagrishan的头长老有问题。几年前,在村庄之间的额外道路上花了一大笔外援资金。但丛林无情地超越了道路,因此大型公路网络的维护成本太高。长老理事会必须选择停止维持一些道路。左上方的地图显示了现在使用的所有道路以及维护它们的每月aacms的成本。当然,即使路线不像以前那么短,也需要在维护道路上的所有村庄之间进行某种方式。首席长老想告诉长老会,他们每月可以花费最少的金额来维持连接所有村庄的道路。在上面的地图中,村庄标有A到I. 右边的地图显示了最便宜的道路,每月216个aacms。你的任务是编写一个可以解决这些问题的程序。 

输入

输入由1到100个数据集组成,后面跟着一个只包含0的最后一行。每个数据集都以一个只包含数字n的行开头,这个数字是村庄的数量,1 <n <27,村庄被标记使用字母表的前n个字母,大写。每个数据集都以n-1行完成,这些行以字母顺序从村庄标签开始。最后一个村庄没有线路。村庄的每条线路都以村庄标签开头,后面跟着一个从这个村庄到村庄的道路数k,后面有字母标签。如果k大于0,则该线继续每条k条道路的数据。每条道路的数据是道路另一端的村庄标签,后面是道路的aacms的每月维护费用。维护成本将是小于100的正整数。行中的所有数据字段由单个空格分隔。道路网络将始终允许所有村庄之间的旅行。该网络永远不会有超过75条道路。没有村庄将有超过15条道路通往其他村庄(在字母表之前或之后)。在下面的示例输入中,第一个数据集与上面的地图一起使用。 

产量

每个数据集的输出为每行一个整数:维持连接所有村庄的道路系统的每月aacms的最低成本。注意:检查每一组可能的道路的强力解决方案将无法在一分钟的时间内完成。 

样本输入

9
A 2 B 12 I 25
B 3 C 10 H 40 I 8
C 2 D 18 G 55
D 1 E 44
E 2 F 60 G 38
F 0
G 1 H 35
H 1 I 35
3
A 2 B 10 C 40
B 1 C 20
0

样本输出

216
30

资源

2002年中美洲中部

这题比较难的地方在于输入把,和常规的建图不一样,给出了字母作为编号,给边的方式也略有不同

    bool operator < (const edge &e) const{//c++自定义比较
        return w>e.w;//小
    }
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
int n,m,k,w,ans;
int f[50];

struct edge{
    int a,b,w;
    bool operator < (const edge &e) const{
        return w>e.w;//小
    }
};

bool cmp(edge a,edge b){
    return a.w < b.w;
}

int find(int x){
    if(f[x]==x)
        return x;

    return f[x] = find(f[x]);
}

void Union(int x,int y,int w){
    int a = find(x);
    int b = find(y);
    if(a!=b){
        f[a] = b;
        ans+=w;
    }
}


int main(){
    while(~scanf("%d",&n),n){
        m = n-1;
        char str;
        priority_queue<edge> pq;
        ans = 0;

        for(int i=0;i<=n;i++)
            f[i] = i;
        while(m--){
            cin>>str>>k;
            char str1;
            while(k--){
                cin>>str1>>w;
                edge e;
                e.a = (str-'A');
                e.b = (str1-'A');
                e.w = w;
                pq.push(e);
            }
        }
        while(!pq.empty()){
            edge u = pq.top();
            pq.pop();
//            cout<<u.a<<" "<<u.b<<" "<<u.w<<"!!!"<<endl;
            Union(u.a,u.b,u.w);
        }
        cout<<ans<<endl;
    }





    return 0;
}

POJ 1287 Networking

输出

您被分配设计广泛区域中某些点之间的网络连接。您将获得该区域中的一组点,以及可连接成对点的电缆的一组可能路线。对于两点之间的每条可能路线,您将获得连接该路线上的点所需的电缆长度。请注意,两个给定点之间可能存在许多可能的路径。假设给定的可能路线(直接或间接)连接该区域中的每两个点。 
您的任务是为该区域设计网络,以便在每两个点之间存在连接(直接或间接)(即,所有点都是互连的,但不一定是通过直接电缆),并且总长度为用过的电缆很小。

输入

输入文件由许多数据集组成。每个数据集定义一个必需的网络。集合的第一行包含两个整数:第一行定义给定点的数量P,第二行定义点之间给定路径的数量R. 以下R行定义了点之间的给定路线,每条线给出三个整数:前两个数字标识点,第三个给出路线的长度。数字用空格分隔。仅给出一个数字P = 0的数据集表示输入的结束。数据集用空行分隔。 
最大点数为50.给定路线的最大长度为100.可能的路线数量不受限制。节点用1和P(含)之间的整数标识。两个点i和j之间的路线可以给出为ij或j i。 

产量

对于每个数据集,在单独的行上打印一个数字,该行显示用于整个设计网络的电缆的总长度。

样本输入

1 0

2 3
1 2 37
2 1 17
1 2 68

3 7
1 2 19
2 3 11
3 1 7
1 3 5
2 3 89
3 1 91
1 2 32

5 7
1 2 5
2 3 7
2 4 8
4 5 11
3 5 10
1 5 6
4 2 12

0

样本输出

0
17
16
26

资源

2002年东南欧

优先队列+并查集  

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;

int n,m,ans=0;
int f[105];

struct edge{
    int u,v,w;
    bool operator < (const edge &e) const{
        return w>e.w;//小
    }
};

int find(int x){
    if(f[x]==x)
        return x;
    return f[x] = find(f[x]);
}

void Union(int x,int y,int w){
    int a = find(x);
    int b = find(y);
    if(a!=b){
        f[a] = b;
        ans += w;
    }
}


int main(){
    while(~scanf("%d",&n),n){
        scanf("%d",&m);
        priority_queue<edge> pq;
        ans = 0;
        for(int i=0;i<=n;i++)
            f[i] = i;

        while(m--){
            edge e;
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            e.u = a;
            e.v = b;
            e.w = c;
            pq.push(e);
        }
        while(!pq.empty()){
            edge e = pq.top();
            pq.pop();
            Union(e.u,e.v,e.w);//还有个小优化就是最小生成树建成就break
        }
        printf("%d\n",ans);
    }

	return 0;
}

POJ 2031 Building a Space Station

描述

您是空间站工程团队的成员,并在该站的施工过程中分配了一项任务。您需要编写一个计算机程序来完成任务。 
空间站由许多单元组成,称为单元。所有细胞都是球形的,但它们的大小不一定是均匀的。在该站成功进入其轨道后不久,每个小区固定在其预定位置。很奇怪,两个细胞可能彼此接触,甚至可能重叠。在极端情况下,细胞可能完全包围另一个细胞。我不知道这样的安排是如何可能的。 

所有细胞必须连接,因为机组成员应该能够从任何细胞走到任何其他细胞。如果,(1)A和B相互接触或重叠,(2)A和B通过“走廊”连接,或者(3)有一个单元格C,它们可以从单元格A走到另一个单元格B.从A到C,从B到C都是可能的。注意,条件(3)应该被传递解释。 

您需要设计一个配置,即哪些单元格对与走廊连接。走廊配置有一些自由。例如,如果存在三个单元A,B和C,彼此不接触或不重叠,则至少三个计划是可能的,以便连接所有三个单元。第一个是建造走廊AB和AC,第二个是BC和BA,第三个是CA和CB。建造走廊的成本与其长度成正比。因此,您应该选择走廊总长度最短的计划。 

您可以忽略走廊的宽度。在两个单元格表面上的点之间构建一个走廊。它可以任意长,但当然选择最短的一个。即使两个走廊AB和CD在空间相交,也不认为它们形成(例如)A和C之间的连接路径。换句话说,您可以认为两条走廊从不相交。 

输入

输入由多个数据集组成。每个数据集以下列格式给出。 


x1 y1 z1 r1 
x2 y2 z2 r2 
... 
xn yn zn rn 

数据集的第一行包含一个整数n,它是单元格的数量。n为正,且不超过100. 

以下n行是细胞的描述。一行中的四个值是球体的中心的x,y和z坐标,以及球体中的半径(在问题的其余部分中称为r),按此顺序。每个值由小数部分给出,小数点后3位。值由空格字符分隔。 

x,y,z和r中的每一个都是正的并且小于100.0。 

输入的结尾由包含零的线表示。 

输出

对于每个数据集,应打印走廊的最短总长度,每个都在一个单独的行中。打印的值应在小数点后3位。它们可能没有大于0.001的误差。 

请注意,如果不需要走廊,也就是说,如果所有单元都没有走廊连接,则走廊的最短总长度为0.000。 

样本输入

3
10.000 10.000 50.000 10.000
40.000 10.000 50.000 10.000
40.000 40.000 50.000 10.000
2
30.000 30.000 30.000 20.000
40.000 40.000 40.000 20.000
5
5.729 15.143 3.996 25.837
6.013 14.372 4.818 10.671
80.115 63.292 84.477 15.120
64.095 80.924 70.029 14.881
39.472 85.116 71.369 5.553
0

样本输出

20.000
0.000
73.834

资源

日本2003年国内

这题太坑了,也就是一个3维的几何+最小生成树裸题,使用d*d<=l1*l1+l2*l2,有大大的误差,明明想避开sqrt的

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cmath>
#include <math.h>

using namespace std;

int n;
double ans=0.0;
int f[105];
double w[105][4];

struct edge{
    int u,v;
    double w;
    bool operator < (const edge &e) const{
        return w>e.w;//小
    }
};

int find(int x){
    if(f[x]==x)
        return x;
    return f[x] = find(f[x]);
}

void Union(int x,int y,double w){
    int a = find(x);
    int b = find(y);
    if(a!=b){
        f[a] = b;
        ans=ans+w;
    }
}



int main(){

    while(~scanf("%d",&n),n){
            ans = 0;
        for(int i=1;i<=n;i++)
            scanf("%lf%lf%lf%lf",&w[i][0],&w[i][1],&w[i][2],&w[i][3]);
        for(int i=0;i<=100;i++)
            f[i] = i;

        priority_queue<edge> pq;

        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++){
                double d = sqrt((w[i][0]-w[j][0])*(w[i][0]-w[j][0]) + (w[i][1]-w[j][1])*(w[i][1]-w[j][1]) + (w[i][2]-w[j][2])*(w[i][2]-w[j][2]));
                if(d<=w[i][3]+w[j][3])
                    Union(i,j,0);
                else{
                    edge e;
                    e.u = i;
                    e.v = j;
                    e.w = d-w[i][3]-w[j][3];
                    pq.push(e);
                }
        }

        while(!pq.empty()){
            edge e = pq.top();
            pq.pop();
            Union(e.u,e.v,e.w);
        }

        printf("%.3f\n",ans);//对于双精度输出,G ++上面要用%f,C ++则用%lf,否则WA
    }

	return 0;
}

 POJ 2421 Constructing Roads

描述

有N个村庄,编号从1到N,你应该建造一些道路,使每两个村庄可以相互连接。我们说两个村A和B是相连的,当且仅当A和B之间有一条道路,或者存在一个村C以便在A和C之间有一条道路,并且C和B相连。 

我们知道一些村庄之间已经有一些道路,你的工作就是修建一些道路,使所有村庄都连通起来,所有道路的长度都是最小的。

输入

第一行是整数N(3 <= N <= 100),这是村庄的数量。然后是N行,其中第i个包含N个整数,这些N个整数中的第j个是村庄i和村庄j之间的距离(距离应该是[1,1000]内的整数)。 

然后是整数Q(0 <= Q <= N *(N + 1)/ 2)。然后是Q行,每行包含两个整数a和b(1 <= a <b <= N),这意味着村庄a和村庄b之间的道路已经建成。

产量

您应该输出一个包含整数的行,该整数是要构建的所有道路的长度,以便连接所有村庄,并且此值最小。

样本输入

3
0 990 692
990 0 179
692 179 0
1
1 2

样本输出

179

资源

北京大学月刊,kicc

#include<iostream>
#include<queue>
#include<cstdio>
using namespace std;

int n,m,Q,ans;
int f[1005];
int mp[1005][1005];

struct edge{
    int u,v,w;
    bool operator < (const edge &e) const{
        return w>e.w;//小
    }
};

int find(int x){
    if(f[x]==x)
        return x;
    return f[x] = find(f[x]);
}

void Union(int x,int y,int w){
    int a = find(x);
    int b = find(y);
    if(a!=b){
        f[a] = b;
        ans+=w;
    }
}

int main(){

    while(~scanf("%d",&n)){
        priority_queue<edge> pq;
        ans = 0;
        for(int i=0;i<=n;i++)
            f[i] = i;

        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++) {
                scanf("%d",&mp[i][j]);
                if(i<j) {
                    edge e;
                    e.u = i;
                    e.v = j;
                    e.w = mp[i][j];
                    pq.push(e);
                }
            }

        scanf("%d",&Q);
        while(Q--){
            int a,b;
            scanf("%d%d",&a,&b);
            Union(a,b,0);
        }
        while(!pq.empty()){
            edge e = pq.top();
            pq.pop();
            Union(e.u,e.v,e.w);
        }
        printf("%d\n",ans);
    }

	return 0;
}

ZOJ 1586 QS Network

 

在星系cgb的w-503行星中,有一种名为QS的智能生物。QS通过网络相互通信。如果两个QS想要连接,他们需要购买两个网络适配器(每个QS一个)和一段网络电缆。请注意,一个网络适配器只能在单个连接中使用。(即,如果QS想要设置四个连接,则需要购买四个适配器)。在通信过程中,QS将其消息广播到它所连接的所有QS,接收消息的QS组将消息广播到它们所连接的所有QS,重复该过程直到所有QS都收到消息。

示例如下所示:


QS网络示例,QS A想要发送消息。

步骤1. QS A向QS B和QS C发送消息; 

步骤2. QS B向QS A发送消息; QS C向QS A和QS D发送消息; 

步骤3.该过程终止,因为所有QS都收到了该消息。

每个QS都有其优质的网络适配器品牌,并始终在其所有连接中购买该品牌。QS之间的距离也不同。考虑到每个QS优先品牌的网络适配器的价格以及每对QS之间的电缆价格,您的任务是编写一个程序来确定设置QS网络的最低​​成本。


输入

输入的第一行包含一个整数t,表示数据集的数量。

从第二行开始,有t个数据集。

在单个数据集中,第1行包含一个表示QS数的整数n。

第二行包含n个整数,表示每个QS最喜欢的网络适配器的价格。

在第3行到第n + 2行包含一个矩阵,表示ecah对QS之间的电缆价格。

限制:

输入中的所有整数都是非负数且不超过1000。


产量

对于每个数据集,输出一行中的最小成本。不需要额外的空行。


样本输入



10 20 30 
0 100 200 
100 0 300 
200 300 0


样本输出

370

每个边的权值还要加上两端点的权值

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;

int n,ans,T;
int w[1005];
int mp[1005][1005];
int f[1005];

struct edge{
    int u,v,w;
    bool operator < (const edge &e) const{
        return w>e.w;//小
    }
};

int find(int x){
    if(f[x]==x)
        return x;
    return f[x] = find(f[x]);
}

void Union(int x,int y,int w){
    int a = find(x);
    int b = find(y);
    if(a!=b){
        f[a] = b;
        ans+=w;
    }
}

int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        priority_queue<edge> pq;
        ans=0;
        for(int i=1;i<=n;i++){
            f[i] = i;
            scanf("%d",&w[i]);
        }

        for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            scanf("%d",&mp[i][j]);
            if(i<j){
                edge e;
                e.u = i;
                e.v = j;
                e.w = mp[i][j] + w[i] + w[j];
                pq.push(e);
            }
        }

        while(!pq.empty()){
            edge e = pq.top();
            pq.pop();
            Union(e.u,e.v,e.w);
        }
        printf("%d\n",ans);
    }

	return 0;
}

POJ 1789 Truck History

描述

Advanced Cargo Movement,Ltd。使用不同类型的卡车。有些卡车用于蔬菜运输,其他用于家具或砖块。该公司有自己的代码描述每种类型的卡车。代码只是一个正好七个小写字母的字符串(每个位置上的每个字母都有一个非常特殊的含义,但这对于此任务来说并不重要)。在公司历史的开始,只使用了一种卡车类型,但后来其他类型都是从它衍生出来的,然后从新类型中衍生出另一种类型,依此类推。 

今天,ACM的财富足以支付历史学家的历史。历史学家试图找出的一件事是所谓的推导计划 - 即卡车类型是如何推导出来的。他们将卡车类型的距离定义为卡车类型代码中具有不同字母的位置数。他们还假设每种卡车类型都来自其他卡车类型(第一种卡车类型除外,这种类型不是来自任何其他类型)。然后将推导计划的质量定义为 

1 /Σ (t o,t d) d(t o,t d)


总和遍历推导计划中的所有类型对,使得t o是原始类型,t d是从它派生的类型,d(t o,t d)是类型的距离。 
由于历史学家失败了,你要编写一个程序来帮助他们。根据卡车类型的代码,您的程序应该找到最高质量的派生计划。 

输入

输入包含几个测试用例。每个测试用例以包含卡车类型数量的行开头,N,2 <= N <= 2 000.以下N行输入中的每一行包含一个卡车类型代码(七个小写字母的字符串)。您可以假设代码唯一地描述卡车,即,这N条线中没有两条是相同的。输入在卡车类型数量的位置以零结束。

产量

对于每个测试用例,您的程序应输出"The highest possible quality is 1/Q.",其中1/Q是最佳推导计划的质量。

样本输入

4 
aaaaaa 
baaaaaa 
abaaaaa 
aabaaaa 
0

样本输出

The highest possible quality is 1/3.

资源

CTU Open 2003

1/Q最大,不就是Q最小吗,还是求最小生成树问题,这里是完全图,kruskal比较慢,prim会快一点

没有m==n-1的break优化,kruskal会超时

#include<iostream>
#include<queue>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<string>
using namespace std;

int n,m,ans=0;
char s[2005][7];
int f[2005];
int w[2005][2005];

struct edge{
    int u,v,w;
    bool operator < (const edge &e) const{
        return w>e.w;//小
    }
};

int find(int x){
    if(f[x]==x)
        return x;
    return f[x] = find(f[x]);
}

void Union(int x,int y,int w){
    int a = find(x);
    int b = find(y);
    if(a!=b){
        f[a] = b;
        ans+=w;
        m++;
    }
}


int main(){
    while(~scanf("%d",&n),n){
        for(int i=1;i<=n;i++){
            scanf("%s",&s[i]);
            f[i] = i;
        }
        priority_queue<edge> pq;
        ans = 0;
        m = 0;

        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++){
                edge e;
                int d=0;
                for(int k=0;k<7;k++){
                    if(s[i][k]!=s[j][k])
                        d++;
                }

                e.u = i;
                e.v = j;
                e.w = d;
                pq.push(e);
            }

        while(!pq.empty()) {
            edge e = pq.top();
            pq.pop();
            Union(e.u,e.v,e.w);
            if(m==n-1)
                break;
        }
        printf("The highest possible quality is 1/%d.\n",ans);
    }

	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_41793113/article/details/88951579