题目链接:Jurassic Jigsaw
题意:点击上面链接自行查看
方法:题目要求的树其实就是最小生成树,这里使用kruskal算法。
kruskal算法简介:在所有边中每次都找边权最小的来组成最小生成树,但是要保证这条边的两个端点属于两个不同的连通块,否则添加完这条边以后就出现了环,既然有环那就不是树了。所以需要判断两个点是否属于同一个连通块,这可以使用并查集实现。
(kruskal不太适合稠密图,稠密图可以使用prim)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll M=1100;
char mp[M][13];
int n,m,a[M];
struct N
{
int u,v,w;
bool operator <(N t)const
{
return w>t.w;
}
};
priority_queue<N> q;//保存边的优先队列,用来找边权最小的边
queue<int> qq;
int fd(int x)
{
return x==a[x]?x:(a[x]=fd(a[x]));
}
void con(int x,int y)
{
int rx=a[x],ry=a[y];
if(rx!=ry)
a[rx]=ry;
}
void ksk() //kruskal
{
int ans=0;
for(int i=0;i<=n;i++)a[i]=i;//初始化并查集
while(!q.empty())
{
N tem=q.top();q.pop(); //找一条边权最小的边
if(fd(tem.u)==fd(tem.v))continue;//如果边的两个端点属于同一个连通分量,则舍弃
ans+=tem.w; //如果两个端点不属于同一个连通分量,则让这条边成为最小生成树中的边
con(tem.u,tem.v);//将这两个点放到同一个连通分量中
qq.push(tem.v);
qq.push(tem.u);
}
printf("%d\n",ans); //最小生成树中所有边权之和
}
int f(int x,int y)
{
int ans=0;
for(int i=0;i<m;i++)
if(mp[x][i]!=mp[y][i])ans++;
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
{
scanf("%s",mp[i]);
}
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
q.push((N){i,j,f(i,j)});
}
ksk();
while(!qq.empty())
{
printf("%d",qq.front());qq.pop();
printf(" %d\n",qq.front());qq.pop();
}
return 0;
}
本文详细介绍了Kruskal算法在求解最小生成树问题中的应用,通过具体实例讲解了算法的实现过程,包括使用优先队列选取最小权重边和并查集判断连通性的关键步骤。
62

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



