解决的主要是什么问题呢,我感觉其实就是连接各点所需要的最小代价之类的问题
什么时候用kruskal/prim


prim算法(二维数组实现)
其实就是点为先,以点去扩展,每次选择的是这个点扩展出边的最小值
cpp
int prim()
{
memset(dist,0x3f,sizeof dist);
dist[1]=0;
int res=0;
for(int i=0;i<n;i++)//一共n个点
{
int t=-1;
//先找到最小的dist的点
for(int j=1;j<=n;j++)
{
if(!st[j]&&(t==-1||dist[j]<dist[t]))
{
t=j;
}
}
st[t]=true;
if(i)res+=dist[t];
//更新其他点
for(int j=1;j<=n;j++)
{
dist[j]=min(dist[j],g[t][j]);
}
}
return res;
}
练习1
cpp
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=510,INF=0x3f3f3f3f;
int n,m;
int dist[N];
bool st[N];
int g[N][N];
int prime()
{
memset(dist,0x3f,sizeof dist);
dist[1]=0;
int res=0;
for(int i=0;i<n;i++)
{
int t=-1;
for(int j=1;j<=n;j++)
{
if(!st[j]&&(t==-1||dist[j]<dist[t]))
{
t=j;
}
}
if(i&&dist[t]==INF)return INF;
if(i)res+=dist[t];
st[t]=true;
for(int j=1;j<=n;j++)
{
dist[j]=min(dist[j],g[t][j]);
}
}
return res;
}
int main()
{
cin>>n>>m;
memset(g,0x3f,sizeof g);
while(m--)
{
int a,b,c;
cin>>a>>b>>c;
g[a][b]=g[b][a]=min(g[a][b],c);
}
int t=prime();
if(t==INF)cout<<"impossible"<<endl;
else cout<<t<<endl;
return 0;
}
练习2
cpp
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N = 5010;
const double INF = 1e18;
int n;
struct node{
int x, y;
} q[N];
double dist[N];
bool st[N];
double distance(int x1, int y1, int x2, int y2)
{
double dx = x1 - x2;
double dy = y1 - y2;
return sqrt(dx*dx + dy*dy);
}
double prim()
{
for(int i = 1; i <= n; i++) dist[i] = INF;
dist[1] = 0;
double res = 0;
for(int i = 1; i <= n; i++)
{
int t = -1;
for(int j = 1; j <= n; j++)
{
if(!st[j] && (t == -1 || dist[j] < dist[t]))
t = j;
}
st[t] = true;
res += dist[t];
for(int j = 1; j <= n; j++)
{
if(!st[j])
{
double d = distance(q[t].x, q[t].y, q[j].x, q[j].y);
if(d < dist[j])
dist[j] = d;
}
}
}
return res;
}
int main()
{
cin >> n;
for(int i = 1; i <= n; i++)
{
cin >> q[i].x >> q[i].y;
}
double res = prim();
printf("%.2f\n", res);
return 0;
}
练习3
cpp
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=210,INF=0x3f3f3f3f;
int n,w;
int g[N][N];
int dist[N];
bool st[N];
int prime()
{
memset(dist,0x3f,sizeof dist);
memset(st,0,sizeof st);
dist[1]=0;
int res=0;
for(int i=0;i<n;i++)
{
int t=-1;
for(int j=1;j<=n;j++)
{
if(!st[j]&&(t==-1||dist[j]<dist[t]))
{
t=j;
}
}
if(i&&dist[t]==INF)return -1;
if(i)res+=dist[t];
st[t]=true;
for(int j=1;j<=n;j++)
{
dist[j]=min(dist[j],g[t][j]);
}
}
return res;
}
int main()
{
cin>>n>>w;
memset(g,0x3f,sizeof g);
for(int i=1;i<=w;i++)
{
int a,b,c;
cin>>a>>b>>c;
g[a][b] = g[b][a] = min(g[a][b], c);
int res=prime();
cout<<res<<endl;
}
return 0;
}
kruskal算法(大部分题目)
先找最小边依次将最小边加入
cpp
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100010;
const int M=200010;
int p[N];
int n,m;
struct EDGE
{
int a,b,w;
}edge[M];
//并查集找父节点
int find(int x)
{
if(p[x]!=x)p[x]=find(p[x]);
return p[x];
}
//结构体排序函数
bool cmp(EDGE a,EDGE b)
{
return a.w<b.w;
}
int main()
{
cin>>n>>m;
for(int i=0;i<m;i++)
{
int x,y,c;
cin>>x>>y>>c;
edge[i].a=x;
edge[i].b=y;
edge[i].w=c;
}
//按照权重从小到大排序
sort(edge,edge+m,cmp);
//并查集初始化
for(int i=0;i<n;i++)p[i]=i;
//res是权重,cnt是边的条数
int res=0,cnt=0;
//kruskal算法:从最小的边开始画,直到把整个图画通。
for(int i=0;i<m;i++)
{
int a=edge[i].a;
int b=edge[i].b;
int w=edge[i].w;
a=find(a),b=find(b);
if(a!=b)
{
p[a]=b;
res+=w;
cnt++;
}
}
if(cnt<n-1)cout<<"impossible"<<endl;
else cout<<res<<endl;
return 0;
}