题目大意:给定n个村庄的距离关系,以及已经连接的路径,以最小的距离连接其它村庄,还需要最小距离为多少?
解题思路:最小生成树的应用,prim的写法是对于以及连接好的我们把权值置为0,这样就能保证连接好的边在最小生成树里。然后记录最小生成树边之和即可。类似于Dijkstra算法的最基础写法。详见code。
题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=1102
Prim code:
<pre name="code" class="cpp">#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN =100+10;
const int INF = 0x3fffffff;
int map[MAXN][MAXN],vis[MAXN],dist[MAXN];
int n,q,a,b;
int Prim(){
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++) dist[i]=(i==1?0:map[1][i]); //初始化
int sum=0;
for(int i=1;i<=n;i++){
int pos,minn=INF;
for(int j=1;j<=n;j++) if(!vis[j] && minn>dist[j]) minn=dist[pos=j]; //选出dist值最小的结点pos
vis[pos]=1; //标记结点
sum+=minn; //记录最小值的和
for(int k=1;k<=n;k++){
if(!vis[k] && dist[k]>map[pos][k]) //更新最小值
dist[k]=map[pos][k];
}
}
return sum;
}
int main(){
while(scanf("%d",&n)!=EOF){
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&map[i][j]);
scanf("%d",&q);
for(int i=1;i<=q;i++){ //如果已经连接则置为0,保证是最小生成树的边
scanf("%d%d",&a,&b);
map[a][b]=map[b][a]=0;
}
int ans=Prim();
printf("%d\n",ans);
}
return 0;
}
再补一个用并查集写的Kruskal。
Kruskal code:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 100+10;
int n,q,a,b,tmp;
int p[MAXN],map[MAXN][MAXN];
struct edge{
int u,v,w;
}e[MAXN*MAXN];
int cmp(const edge a,const edge b){return a.w<b.w;} //间接排序函数
int find(int x){return p[x]==x?x:p[x]=find(p[x]);} //并查集的find函数
int Kruskal(){
int ans=0;
for(int i=0;i<tmp;i++){
int x=find(e[i].u);//找到当前边的两个端点的集合
int y=find(e[i].v);
if(x!=y){//不在同一个集合则合并,记录该边的权值
p[x]=y;
ans+=e[i].w;
}
}
return ans;
}
int main(){
while(scanf("%d",&n)!=EOF){
tmp=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&map[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<i;j++){//因为是单向的,所以只记录左下角部分
e[tmp].u=i;
e[tmp].v=j;
e[tmp++].w=map[i][j];
}
sort(e,e+tmp,cmp); //排序
for(int i=0;i<=n;i++) p[i]=i; //初始化并查集
scanf("%d",&q);
for(int i=0;i<q;i++){
scanf("%d%d",&a,&b);
int x=find(a);//找到当前边的两个端点的集合
int y=find(b);
if(x!=y) p[x]=y; //不在同一个集合则合并
}
int ans=Kruskal();
printf("%d\n",ans);
}
return 0;
}