1.题目编号:1001
2.简单题意:有N个村庄,你需要建造道路使所有的村庄可以连在一起,如果有ABC三个村庄,AB之间有一条道路,AC之间也有一条道路,那么BC之间因为这两条线也能连在一起。我们已经知道有的村庄之间有已经建造的道路,求使所有村庄连在一起需要再建造的道路的最小值。
3.解题思路形成过程:看到这个题就想到是一个求最小生成树的,但是他给定了一些已经建造好的道路。每条边有三个属性,起点、终点和权值,如果起点和终点相反,只记录一个就可以,然后用一个数组将每个顶点初始化为1到n,如果已经建造好的道路则把起点和终点都置成起点值,然后调用自己写的Kruskal函数,记录m减去q个边的权值和。
4.感悟:在数据结构上学习到了图,其中求图的最小生成树学了两种方法,prim算法和kruskal算法。虽然老师在讲的时候很简单,在纸上找到一个图的最小生成树也很容易,但是真的等到写代码的时候还是无从下手。现在可以用上这方面的知识了,而且数据结构快要考试了,正好复习一下~
5.AC的代码:
#include<iostream>
#include<algorithm>
using namespace std;
struct node{
int from;
int to;
int w;
};
node edge[102*100];
int parent[102];
bool cmp(node a,node b)
{
if(a.w<=b.w) return true;
return false;
}
//查找已经建完道路的顶点
int find(int a)
{
if(a!=parent[a])
return find(parent[a]);
else return a;
}
int kruskal(int n,int m)
{
sort(edge,edge+m,cmp);//将边的权值从小到大排序
int i,x,y,ans=0;
for(i=0;i<m;i++)
{
x=edge[i].from;
y=edge[i].to;
x=find(x);
y=find(y);
if(x!=y)
{
ans+=edge[i].w;
parent[y]=x;
}
}
return ans;
}
int main()
{
int n,q,k,i,j,m;
while(cin>>n)
{
m=0;
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
cin>>k;
if(i>=j) continue;//标记过的不用重复记录
edge[m].from=i;
edge[m].to=j;
edge[m].w=k;
m++;
}
}
for(k=1;k<=n;k++)
parent[k]=k;
cin>>q;
//将建完的道路的起点和终点都置为相同的起点
for(k=1;k<=q;k++)
{
cin>>i>>j;
i=find(i);
j=find(j);
parent[j]=i;
}
//n个点,m条边
cout<<kruskal(n,m)<<endl;
}
return 0;
}
原题:
3 0 990 692 990 0 179 692 179 0 1 1 2
179