传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1102
题意:先给你一个邻接矩阵,然后给你几个已连接的点,求没连接的几块最少要多长的线连接。
一、Prim算法
思路:按点分为S T两块,每次从T块中取出一个点,放入S中。取点满足:T中与S块距离最近的。因为每次取的都是最小边,故可保证连接线最小。
AC代码:
#include<iostream>
using namespace std;
#define INF 0x3f3f3f3f
int n,ans;
int map[101][101];
int dis[101],vis[101];
//vis界定S T集合;dis记录S T最短距离
void Prim()
{
for(int i=1;i<=n;i++)
{
dis[i]=map[1][i];
vis[i]=0;
}
dis[1]=0;
vis[1]=1;
//预处理地图
int k,tmp;
for(int i=1;i<=n;i++)
{
tmp=INF;
for(int j=1;j<=n;j++) //这个循环找出T中距S最近的点
if(!vis[j]&&tmp>dis[j])
{
k=j;
tmp=dis[j];
}
if(tmp==INF) break;//如果找不到,证明T没有点了,退出
vis[k]=1; //找到了,放入S集合
ans+=dis[k]; //加上最短距离
for(int j=1;j<=n;j++) //这个循环更新 加入新点后S与T的最短距离
if(!vis[j]&&dis[j]>map[k][j])
dis[j]=map[k][j];
}
}
int main()
{
while(cin>>n)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>map[i][j];//建立地图
int k,a,b;
cin>>k;
while(k--)
{
cin>>a>>b;
map[a][b]=map[b][a]=0; //已连接的不用再考虑,所以清零
}
ans=0;
Prim();//Prim算法处理
cout<<ans<<endl;
}
return 0;
}
二、Kruskal算法
思路:按连接线的长短排序,然后按照顺序判断两点是否已连接,如果已连接则continue,否则加上这条连接线。
AC代码:
#include<iostream>
#include<algorithm>
using namespace std;
struct node
{
int u,v;
int cap;//记录u到v的距离
}edge[10001];
int n,cnt,ans;
int father[101];
//
void addedge(int cu,int cv,int cw)
{
edge[cnt].cap=cw;
edge[cnt].u=cu;
edge[cnt].v=cv;
cnt++;
}
//将每个点的父节点置为自己
void makeSet()
{
for(int i=1;i<=n;i++)
{
father[i]=i;
}
}
//查找父节点
int findSet(int x)
{
if(x!=father[x])
{
father[x]=findSet(father[x]);
}
return father[x];
}
//定义结构体排序方式
bool cmp(node a,node b)
{
return a.cap<b.cap;
}
//
void Kruskal()
{
sort(edge,edge+cnt,cmp);
for(int i=0;i<cnt;i++)
{
int fx=findSet(edge[i].u);
int fy=findSet(edge[i].v);
if(fx==fy) continue;
ans+=edge[i].cap;//加上这条线
father[fy]=fx;//连通线
}
}
int main()
{
while(cin>>n)
{
makeSet();
cnt=0;
int w;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cin>>w;
addedge(i,j,w);
}
}
int k,a,b;
cin>>k;
while(k--)
{
cin>>a>>b;
int fx=findSet(a);
int fy=findSet(b);
father[fy]=fx;
}
ans=0;
Kruskal();
cout<<ans<<endl;
}
return 0;
}