关于【最小生成树】

题目1017:还是畅通工程

题目描述:

    某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。
输入:

测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
    当N为0时,输入结束,该用例不被处理。

输出:

对每个测试用例,在1行里输出最小的公路总长度。

样例输入:
3
1 2 1
1 3 2
2 3 4
4
1 2 1
1 3 4
1 4 1
2 3 3
2 4 2
3 4 5
0
样例输出:
3
5
来源:
2006年浙江大学计算机及软件工程研究生机试真题
代码如下:

#include <iostream>
#include <stdio.h>

using namespace std;

struct Edge{
    int a;
    int b;
    int cost;
}edge[6000];

int findRoot(int Tree[],int x){
    if(Tree[x]==-1)
        return x;
    else{
        int temp=findRoot(Tree,Tree[x]);
        Tree[x]=temp;
        return temp;
    }
}

void sortEdge(Edge edge[],int n){
    for(int i=1;i<=n-1;i++){
        for(int j=i+1;j<=n;j++){
            if(edge[i].cost>edge[j].cost){
                Edge temp;
                temp.a=edge[i].a;
                temp.b=edge[i].b;
                temp.cost=edge[i].cost;
                edge[i].a=edge[j].a;
                edge[i].b=edge[j].b;
                edge[i].cost=edge[j].cost;
                edge[j].a=temp.a;
                edge[j].b=temp.b;
                edge[j].cost=temp.cost;
            }
        }
    }
}

int main()
{
    int N;
    int Tree[100];
    while(scanf("%d",&N)!=EOF&&N!=0){
        for(int i=1;i<=N*(N-1)/2;i++){
            scanf("%d%d%d",&edge[i].a,&edge[i].b,&edge[i].cost);
        }
        sortEdge(edge,N*(N-1)/2);
        for(int i=1;i<=N;i++)
            Tree[i]=-1;
        int sum=0;
        for(int i=1;i<=N*(N-1)/2;i++){
            int root_a=findRoot(Tree,edge[i].a);
            int root_b=findRoot(Tree,edge[i].b);
            if(root_a!=root_b){
                Tree[root_b]=root_a;
                sum+=edge[i].cost;
            }
        }
        printf("%d\n",sum);
    }
    return 0;
}

/**************************************************************
    Problem: 1017
    User: lcyvino
    Language: C++
    Result: Accepted
    Time:80 ms
    Memory:1588 kb
****************************************************************/

题目1144:Freckles

题目描述:

In an episode of the Dick Van Dyke show, little Richie connects the freckles on his Dad‘s back to form a picture of the Liberty Bell. Alas, one of the freckles turns out to be a scar, so his Ripley‘s engagement falls through. 
    Consider Dick‘s back to be a plane with freckles at various (x,y) locations. Your job is to tell Richie how to connect the dots so as to minimize the amount of ink used. Richie connects the dots by drawing straight lines between pairs, possibly lifting the pen between lines. When Richie is done there must be a sequence of connected lines from any freckle to any other freckle.

输入:

The first line contains 0 < n <= 100, the number of freckles on Dick‘s back. For each freckle, a line follows; each following line contains two real numbers indicating the (x,y) coordinates of the freckle.

输出:

Your program prints a single real number to two decimal places: the minimum total length of ink lines that can connect all the freckles.

样例输入:
3
1.0 1.0
2.0 2.0
2.0 4.0
样例输出:
3.41
来源:
2009年北京大学计算机研究生机试真题
代码如下:

#include <iostream>
#include <stdio.h>
#include <math.h>

using namespace std;

struct point{
    double x;
    double y;
}buf[101];    //记录输入的结点信息

struct Edge{
    int a;
    int b;
    double cost;
}edge[6000];  //记录边的信息

double getDistance(point A,point B){    //计算2点之间的距离
    double temp=(A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y);
    return sqrt(temp);
}

int findRoot(int Tree[],int x){   //寻找结点的根结点
    if(Tree[x]==-1)
        return x;
    else{
        int temp=findRoot(Tree,Tree[x]);
        Tree[x]=temp;
        return temp;
    }
}

void sortEdge(Edge edge[],int n){  //对生成的边按照权值的从小到大进行排序
    for(int i=1;i<=n-1;i++){
        for(int j=i+1;j<=n;j++){
            if(edge[i].cost>edge[j].cost){    //很傻逼的交换
                Edge temp;
                temp.a=edge[i].a;
                temp.b=edge[i].b;
                temp.cost=edge[i].cost;
                edge[i].a=edge[j].a;
                edge[i].b=edge[j].b;
                edge[i].cost=edge[j].cost;
                edge[j].a=temp.a;
                edge[j].b=temp.b;
                edge[j].cost=temp.cost;
            }
        }
    }
}

int main()
{
    int n;
    int Tree[101];   //用于记录每个点的双亲结点
    while(scanf("%d",&n)!=EOF&&n!=0){
        for(int i=1;i<=n;i++){
            scanf("%lf%lf",&buf[i].x,&buf[i].y);  //输入坐标的信息,存储在buf数组内
        }
        for(int i=1;i<=n;i++){   //类似于初始化,把每个点的双亲结点置为-1
            Tree[i]=-1;
        }
        int loc=1;//用于记录边的条数
        for(int i=1;i<=n-1;i++){      //开始计算每条边的信息,包括边两端相连的结点
            for(int j=i+1;j<=n;j++){  //还有边的权值
                edge[loc].a=i;
                edge[loc].b=j;
                edge[loc].cost=getDistance(buf[i],buf[j]);
                loc++;
            }
        }
        loc--;                      //一共有多少条边
        sortEdge(edge,loc);
        double sum=0;               //算总的权值大小
        for(int i=1;i<=loc;i++){
            int root_a=findRoot(Tree,edge[i].a);
            int root_b=findRoot(Tree,edge[i].b);
            if(root_a!=root_b){             //如果两个点不属于一个集合,那么连接这两个坐标的边
                Tree[root_b]=root_a;        //可以作为最小生成树里的 一条边
                sum+=edge[i].cost;
            }
        }
        printf("%.2lf\n",sum);
    }
    return 0;
}

/**************************************************************
    Problem: 1144
    User: lcyvino
    Language: C++
    Result: Accepted
    Time:330 ms
    Memory:1616 kb
****************************************************************/

时间: 2024-09-28 14:09:22

关于【最小生成树】的相关文章

次最小生成树 模版

次小生成树(转) 转载(http://www.cnblogs.com/z360/p/6875488.html) 所谓次小生成树,顾名思义就是从生成树中取出的第二小的生成树. 我们在前面已经说过最小生成树的概念及代码实现了,所以接下来要说的次小生成树应该比较简单理解了. 求次小生成树的两种方法 1:首先求出最小生成树T,然后枚举最小生成树上的边,计算除了枚举的当前最小生成树的边以外的所有边形成的最小生成树Ti,然后求最小的Ti就是次小生成树.2:首先计算出最小生成树T,然后对最小生成树上任意不相邻

HDU1863 畅通工程---(最小生成树)

畅通工程 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 27972    Accepted Submission(s): 12279 Problem Description 省政府"畅通工程"的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可).经过调查评估,得到的统计表中列出

51Nod1601 完全图的最小生成树计数

传送门 我居然忘写题解啦!(记忆废) 不管怎么说,这题还算是一道好题啊--你觉得敦爷出的题会有水题么 -- 这题比较容易把人误导到Boruvka算法之类的东西上去(我们机房去刚D题的人一开始大多也被误导了),但仔细思考之后是可以发现问题的特殊性质的. 听说很多人是从Kruskal算法想到这道题的做法的?好吧我并不是,那我就写写我的思考过程好了-- 记得算导上有一道思考题,判断一个最小生成树算法的正确性.那个算法是这样的:把当前图的点集随意划分成两半,递归两半后选出连接两个点集的边中权值最小的一条

最小生成树求法 Prim + Kruskal

prim算法的思路 和dijkstra是一样的 每次选取一个最近的点 然后去向新的节点扩张 注意这里的扩张 不再是 以前求最短路时候的到新的节点的最短距离 而是因为要生成一棵树 所以是要连一根最短的连枝 所以关键部分修改一下 dist[u] = min(dist[u], e.cost) --->>e是连接 v 和 u的边 同样地 普同写法O(v^2) 用队列优化后O(E*logV) 1 #include <iostream> 2 #include <stdio.h> 3

UVALive-7303- Aquarium【最小生成树】【连通块】

UVALive - 7303- Aquarium 题目链接:7303 题目大意:给你一个r * c的格子,每个格子有一个 ' \ ' 或者 '/' 的墙,以及打掉墙的费用,问使得所有块联通的最小费用.(看图好理解) 题目思路:就是将他化成一个图,联通的块相当于一个点,两个点之间有一条边,边的权值为墙的费用. 转化为连通块的思路是:每个格子看成两部分,左侧和右侧.以一行来看,假设两个格子A,B.那么B格子的右侧的编号一定和A格子的左侧的编号相同.如图所示 给每个格子的左右侧标上号,然后加入边,边的

BZOJ_1016_[JSOI2008]_最小生成树计数_(dfs+乘法原理)

描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1016 给出一张图,其中具有相同权值的边的数目不超过10,求最小生成树的个数. 分析 生成树的计数有一个什么什么算法... 我真的企图研究了...但是智商捉急的我实在看不懂论文... 所以最后还是写了暴力... 当然暴力也要靠正确的姿势的. 首先来看一个结论: 同一张图的所有最小生成树中,边权值相同的边的数目是一定的. 也就是说,假如某一张图的某一棵最小生成树由边权值为1,1,2,2,2,3的

poj1861 最小生成树 prim &amp; kruskal

// poj1861 最小生成树 prim & kruskal // // 一个水题,为的只是回味一下模板,日后好有个照应不是 #include <cstdio> #include <algorithm> #include <cstring> #include <vector> #include <iostream> using namespace std; const int MAX_N = 1008; const int INF =

hdu 1875 畅通工程再续(kruskal算法计算最小生成树)

畅通工程再续 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 18411    Accepted Submission(s): 5769 Problem Description 相信大家都听说一个"百岛湖"的地方吧,百岛湖的居民生活在不同的小岛中,当他们想去其他的小岛时都要通过划小船来实现.现在政府决定大力发展百岛湖,发展首先

【BZOJ】【1016】【JSOI2008】最小生成树计数

Kruskal/并查集+枚举 唉我还是too naive,orz Hzwer 一开始我是想:最小生成树删掉一条边,再加上一条边仍是最小生成树,那么这两条边权值必须相等,但我也可以去掉两条权值为1和3的,再加上权值为2和2的,不也满足题意吗?事实上,如果这样的话……最小生成树应该是1和2,而不是1和3或2和2!!! 所以呢?所以对于一个图来说,最小生成树有几条边权为多少的边,都是固定的!所以我们可以做一遍Kruskal找出这些边权,以及每种边权出现的次数.然后,对于每种边权,比方说出现了$v_i$

最小生成树 Prim(普里姆)算法和Kruskal(克鲁斯特尔)算法

Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小.该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现:并在1957年由美国计算机科学家罗伯特·普里姆(英语:Robert C. Prim)独立发现:1959年,艾兹格·迪科斯彻再次发现了该算法.因此,在某些场