二. 最小生成树
Prim 普里姆算法
思路: 该算法采用贪心思想,在图中任意选择一结点构建一颗生成树然后从所有与该生成树相邻的结点中取出最近的结点和边加入到生成树中.直到所有的结点都加入到该生成树中.
算法复杂度 ElogV
一般采用最小优先队列存放剩余的结点,每次从该最小队列中选出与生成树之间最小的结点加入生成树中,同时更新最小队列.
Description
Farmer John has been elected mayor of his town! One of his campaign promises was to bring internet connectivity to all farms in the area. He needs your help, of course.
Farmer John ordered a high speed connection for his farm and is going to share his connectivity with the other farmers. To minimize cost, he wants to lay the minimum amount of optical fiber to connect his farm to all the other farms.
Given a list of how much fiber it takes to connect each pair of farms, you must find the minimum amount of fiber needed to connect them all together. Each farm must connect to some other farm such that a packet can flow from any one farm to any other farm.
The distance between any two farms will not exceed 100,000.
Input
The input includes several cases. For each case, the first line contains the number of farms, N (3 <= N <= 100). The following lines contain the N x N conectivity matrix, where each element shows the distance from on farm to another. Logically, they are N lines of N space-separated integers. Physically, they are limited in length to 80 characters, so some lines continue onto others. Of course, the diagonal will be 0, since the distance from farm i to itself is not interesting for this problem.
Output
For each case, output a single integer length that is the sum of the minimum length of fiber required to connect the entire set of farms.
Sample Input
4
0 4 9 21
4 0 8 17
9 8 0 16
21 17 16 0
Sample Output
28
大概意思就是给你一个n*n二维数组,行列代表点到点的值,求所产生的最小生成树
题解,典型的最小生成树模板,这里采用prim算法实现,下面是已经ac代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include<iostream>
#include<cmath>
#define LL long long
using namespace std;
#define xi
#define xx 0x3f3f3f3f//定义一个很大的值,拿已经的最小生成树到其他的点的时候需要用到
int map[106][106];//存图
int vis[10086];//标记当前的节点是否已入最小生成树
int low[10086];//存已知最小生成树带其他节点的最小值
int t;//输入二维数组大小
int prim(){
int ans=0;//最小生成树的值
int x=0;//从0节点开始
memset(vis,0,sizeof(vis));
for(int a=0;a<t;a++)
low[a]=map[x][a];//从0到其他节点的最小值
vis[x]=1;//标记已经使用
for(int a=0;a<t-1;a++){
int min=xx;
for(int a=0;a<t;a++)
if(vis[a]==0&&min>low[a])
min=low[a],x=a;//查找最小值,并记录节点
ans+=min;//加入最小值
vis[x]=1;
for(int a=0;a<t;a++)
if(vis[a]==0&&low[a]>map[x][a])//更新从当前的新节点到其他节点的值,判断是否比已知的最小生成树小,如果小 就更新
low[a]=map[x][a];
}
return ans;
}
int main()
{
#ifdef xin
freopen("1.txt", "r", stdin);
#endif
while(cin>>t&&t){
for(int a=0;a<t;a++){
for(int b=0;b<t;b++)
cin>>map[a][b];
}
int sum=prim();
printf("%d\n",sum);
}
return 0;
}
克鲁斯卡尔
克鲁斯卡尔算法每次从剩余的边中选择一个最小的边,如果当前边和已选取的边构成回路,则放弃该并选择下一个最小边。如果不构成回路则将该边以及连接的两个结点加入的生成树中.直到完成整棵生成树的构建.
时间复杂度, ElogE
Description
You are assigned to design network connections between certain points in a wide area. You are given a set of points in the area, and a set of possible routes for the cables that may connect pairs of points. For each possible route between two points, you are given the length of the cable that is needed to connect the points over that route. Note that there may exist many possible routes between two given points. It is assumed that the given possible routes connect (directly or indirectly) each two points in the area.
Your task is to design the network for the area, so that there is a connection (direct or indirect) between every two points (i.e., all the points are interconnected, but not necessarily by a direct cable), and that the total length of the used cable is minimal.
Input
The input file consists of a number of data sets. Each data set defines one required network. The first line of the set contains two integers: the first defines the number P of the given points, and the second the number R of given routes between the points. The following R lines define the given routes between the points, each giving three integer numbers: the first two numbers identify the points, and the third gives the length of the route. The numbers are separated with white spaces. A data set giving only one number P=0 denotes the end of the input. The data sets are separated with an empty line.
The maximal number of points is 50. The maximal length of a given route is 100. The number of possible routes is unlimited. The nodes are identified with integers between 1 and P (inclusive). The routes between two points i and j may be given as i j or as j i.
Output
For each data set, print one number on a separate line that gives the total length of the cable used for the entire designed network.
Sample Input
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
Sample Output
0
17
16
26
题目大意是给你一个P个节点的图,然后R行的信息,每行表示从开始节点,结束节点,2个节点之间的值
题解,典型的最小生成树模板,这里采用克鲁斯卡尔算法解决,这个算法就是贪心最小的边,然后维护一个并查集。已经ac代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include<iostream>
#define LL long long
using namespace std;
#define xi
struct xs
{
int x,y,v;//开始节点,结束节点,值
bool operator <(const xs &A)const
{
return v<A.v;//按值得大小进行排序
}
}s[10086];
int ans=0;
int F[10086];//维护并查集需要
int F1(int x)
{
return F[x]==x?x:F[x]=F1(F[x]);
}
int main()
{
#ifdef xin
freopen("1.txt", "r", stdin);
#endif
int T;int N;
while(cin>>T>>N&&T){
for(int a=0;a<N;a++)
cin>>s[a].x>>s[a].y>>s[a].v;
sort(s,s+N);//对值进行排序
for(int a=0;a<=N;a++)
F[a]=a;//表示所有的节点都未使用
int sum=0;
for(int a=0;a<N;a++)//对已经排序的节点进行遍历,从最小的开始
{
int _u=F1(s[a].x);int _v=F1(s[a].y);//判断是否在并查集里面
if(_v!=_u)
{
F[_v]=F[_u];
sum+=s[a].v;
}
}
cout<<sum<<endl;
}
return 0;
}