从某⼀个顶点开始构建⽣成树;每次将代价最⼩的新顶点纳⼊⽣成树,直到所有顶点都纳⼊为⽌。
算法描述:
最小生成树生成的树可能不同,但是最小的权值肯定是一样的并且是最小的。
通过上小两个图可以看出图不同但是权值相同,权值相同都是15;
另一种构造方式如下图
时间复杂度:O(n^2) 适合⽤于边稠密图
int prim(int k){//从顶点k开始构建最小生成树
memset(book,0,sizeof(book));//初始化标记数组
count=0;//初始化已经标记的点个数
sum=0;//初始化权重
for(i=1;i<=n;i++){//初始化所有顶点
dis[i]=e[k][i];//其余顶点与顶点k的最小距离
}
book[1]=1;//标记k点
count++;//更新点个数
while(count<n){//循环遍历各个点
min=inf;
for(i=1;i<=n;i++){//遍历所有点
if(book[i]==0&&dis[i]<min){//找到离树的最小权重并且没有被标记的点
min=dis[i];
j=i;//找到离树的最小权重的下标
}
}
book[j]=1;//标记当前点
count++;更新点个数
sum+=dis[j];加上权重
for(k=1;k<=n;k++){//遍历所有点更新到树的最小权重
if(book[k]==0&&dis[k]>e[j][k]){//若有更小的权重
dis[k]=e[j][k];//更新dis
}
}
return sum;
}
传送门
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*N代表成本情况,如21代表1->4花费21,17代表2->4花费17.。。。
解题思路:
最小生成树模板题
#include
#include
int n,m,i,j,min,k,t;
int e[1005][1005],dis[10005],book[100000];
int inf=99999999;
int count=0,sum=0;
void prim(){
memset(book,0,sizeof(book));
count=0,sum=0;
for(i=1;i<=n;i++){
dis[i]=e[1][i];
}
book[1]=1;
count++;
while(count<n){
min=inf;
for(i=1;i<=n;i++){
if(book[i]==0&&dis[i]<min){
min=dis[i];
j=i;
}
}
book[j]=1;
count++;
sum+=dis[j];
for(k=1;k<=n;k++){
if(book[k]==0&&dis[k]>e[j][k])
dis[k]=e[j][k];
}
}
}
int main(){
while(scanf("%d",&n)!=EOF){
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
e[i][j]=inf;
}
}
for(i=1;i<=n;i++)
for(j=1;j<=n;j++){
scanf("%d",&e[i][j]);
}
prim();
printf("%d\n",sum);
}
return 0;
}
每次选择⼀条权值最⼩的边,使这 条边的两头连通(原本已经连通的就不选)
直到所有结点都连通
算法基本思想:
Kruakal算法的基本思想是每次都选取不会形成环的权值最小的边,但与Prim不同的是,Kruskal算法引入了连通分量来判断是否形成环。所以难点在于如何判断两个顶点是否属于同一连通分量。我们可以用并查集的思想,直接将同一连通分量的两个顶点的根 father[] 连在一起。也就是说当新的一条边加入时,判断它的两个顶点是否属于一个连通分量,即判断他们的根father[]是否相同。
遍历排序好的边集V进行如下选取,直到选取边数为n-1时
步骤1:选取未选取过的权值最小的边E(i, j)
步骤2:如果顶点i和j位于两个不同的连通分量,则选取边E(i,j)加入边集S,同时将边(i, j)的连通分量连在在一起。
步骤3:继续执行步骤1和2,直到选取边数为n-1时生成最小生成树
时间复杂度:O( |E|log2|E| ) 适合⽤于边稀疏图
int Kruskal()
{
sort(t+1, t+m+1,cmp);//排序
for(遍历所有顶点) S[i]=i;//并查集初始化自身为一个集合
int total=0;//所选取的边数
int sum=0;//权重和
for(遍历排序后的所有边){
if(total==n-1) break; //直到选取了n-1条边后跳出循环
int x=edge[i].u,y=edge[i].v;
if(find(x)!=find(y)){//若不是同一集合也就是判断是否有环
sum+=edge[i].w;//选取这条边
merge(x,y);//加入同一集合
total++;
}
}
return sum;//返回权重和
}
传送门
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
题意描述:
题意 :给定两个点及其边权值,求出各点权值和最小的值(即生成最小生成树)
解题方法:最小生成树
这道题是一棵裸的最小二叉树,即克鲁斯卡尔算法(kruskal),算法大概内容是,首先对所有的边权值进行排序,并判断两个顶点是否连通,判断方法可借鉴并查集思想,将所有的点放入并查集中,判断两个顶点是否连通,即判断顶点是否属于一个集合内,以提升算法效率。可以用邻接矩阵存储边权值,不过在相同点之间存在多个权值时,需要取最小的权。
#include
#include
using namespace std;
struct edge
{
int u;
int v;
int w;
};
struct edge e[1000010],t;
int n,m;
int f[100010]={0},sum=0,count=0;
//sort排序cmp
bool cmp(edge a,edge b)
{
return a.w<b.w;
}
//并查集
int getf(int v)
{
if(f[v]==v)
{
return v;
}
else
{
f[v]=getf(f[v]);
return f[v];
}
}
int merge(int v,int u)
{
int t1,t2;
t1=getf(v);
t2=getf(u);
if(t1!=t2)
{
f[t2]=t1;
return 1;
}
return 0;
}
int main()
{
int i;
while(scanf("%d %d",&n,&m)&&n!=0)
{
int sum=0,count=0;
for(i=1;i<=m;i++)
{
scanf("%d %d %d",&e[i].u,&e[i].v,&e[i].w);
}
sort(e+1,e+m+1,cmp);
//Kruskal算法
for(i=1;i<=n;i++)
{
f[i]=i;
}
for(i=1;i<=m;i++)
{
if(merge(e[i].u,e[i].v))//并查集判断是否有环
{
count++;
sum+=e[i].w;
}
if(count==n-1)
break;
}
printf("%d\n",sum);
}
return 0;
}