题意:给定n个村庄(顶点),给定各村庄之间直线距离,一个n*n的二维数组,第I行第j列的值代表顶点I到j的距离,然后是q个已经修好路的村庄,要求是修最短的路,使得所有村庄相互连通。
思路:将已经修好路的各村庄的权值变为0,求最小生成树。注意图是完全图,边数是n*n-1 / 2。
当作模板用一用吧
克鲁斯卡尔算法思想:从小到大考虑每一条边,一开始生成树为空树,如果边两端点不在生成树中,将边加入生成树中,否则不考虑当前边,直到树的条件达成
树的边与点之间的关系:e边数=n顶点数-1
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 110;
int a[maxn][maxn];
int f[maxn];
int n,en;
struct edge
{
int w;
int from,to;
};
vector<edge> e;
bool cmp(edge a,edge b)
{
return a.w<b.w;
}
void addedge(int from,int to,int w)
{
edge Edge={w,from,to};
e.push_back(Edge);
}
int Find(int x)
{
if(f[x]==x)return x;
else return f[x]=Find(f[x]);
}
int Kuscal()
{
int ans=0;
for(int i=1;i<=n;i++)f[i]=i;
for(int i=0;i<e.size();i++)
{
int u=e[i].from;
int v=e[i].to;
int x=Find(u);
int y=Find(v);
if(x==y)continue;
f[x]=y;
ans+=e[i].w;
en++;
if(en==n-1)break;
}
return ans;
}
int main()
{
// freopen("in.txt","r",stdin);
while(~scanf("%d",&n))
{
e.clear();// 注意!
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]);
int q,u,v;
scanf("%d",&q);
en=0;
while(q--)
{
scanf("%d%d",&u,&v);
if(u>v)swap(u,v);
a[u][v]=0;
}
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
addedge(i,j,a[i][j]);
}
}
sort(e.begin(),e.end(),cmp);
printf("%d\n",Kuscal());
}
}
本文介绍了一个基于克鲁斯卡尔算法求解最小生成树的问题实例,包括了如何构建完全图、如何处理已连接村庄的特殊权值设置,并通过C++代码实现了算法流程。
419

被折叠的 条评论
为什么被折叠?



