第一行国际惯例咕咕咕。
第二行——欠的东西总是要还的——来自一个上次写kruskal把prim抛之脑后然后忘了的人。
以下是正文:
1.prim的思路也是贪心,不过以点为主
2.先任意选取一点标记为访问过,找到与其相连的mincost的点,放到集合内,标记为访问过
3.遍历集合内的点,找到与任一点相连的mincost(且需未访问过)
4.重复上面的步骤
5.当有n个点 or n-1条边时停止
6.因为在不停地选点,所以适用于稠密图
7.时间复杂度为O(n^2)
下附题目:
1.HDU1233 代码注释中有详解
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define ll long long
#define inf 0x3f3f3f3f
//时间复杂度O(n^2)
using namespace std;
int n;
int tu[105][105];
bool vis[105];
int dis[105];
int prim()
{
int ans = 0;
vis[1] = 1;//选取1为根节点
for(int i = 2; i <= n; ++i)
dis[i] = tu[1][i];//记录下1到i点的距离
for(int i = 2; i <= n; ++i)//还需选择n-1个点
{
int xb;
int cost = inf;
for(int j = 1; j <= n; ++j)
{
if(vis[j] == 0 && cost > dis[j])
{
xb = j;
cost = dis[j];
}
}//一遍后找到了与当前集合内的点连通的mincost
vis[xb] = 1;//标记该点为访问过
ans += cost;//更新ans
for(int j = 1; j <= n; ++j)
{
if(vis[j] == 0 && dis[j] > tu[xb][j])
dis[j] = tu[xb][j];
}//在未访问过的点中,找mincost
//不一定为当前加入点到j点,可能为前面已构造的点到j点
//更新后即为集合内(已使用过的点)的点到j的mincost
}
return ans;
}
int main()
{
while(~scanf("%d",&n))
{
memset(tu,inf,sizeof(tu));
memset(vis,0,sizeof(vis));
if(n == 0)
break;
for(int i = 0; i < n*(n-1)/2; ++i)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
tu[a][b] = c;
tu[b][a] = c;
}
int res = prim();
printf("%d\n",res);
}
return 0;
}
此处有个疑问,希望大佬帮忙解答qwq:不需要判断新加入的点与之前的点有没有成环吗?留个坑。
2.SDNU1229
思路:大体思路跟HDU的一样,只不过输入的是点的座标,需要跑两层循环处理一下任意两个点之间的距离,而且因为数据范围在n <= 1000,最多有499500条边,稠密图,用prim更好。(当然出题人也表示用kruskal会T(但HDU那个是可以用kruskal的
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
int n;
double tu[1005][1005];
bool vis[1005];
double dis[1005];
double prim()
{
double ans = 0;
vis[1] = 1;
for(int i = 2; i <= n; ++i)
dis[i] = tu[1][i];
for(int i = 2; i <= n; ++i)
{
int xb;
double cost = inf;
for(int j = 1; j <= n; ++j)
{
if(vis[j] == 0 && cost > dis[j])
{
xb = j;
cost = dis[j];
}
}
vis[xb] = 1;
ans += cost;
for(int j = 1; j <= n; ++j)
{
if(vis[j] == 0 && dis[j] > tu[xb][j])
dis[j] = tu[xb][j];
}
}
return ans;
}
int main()
{
while(~scanf("%d",&n))
{
double x[1005],y[1005];
memset(tu,inf,sizeof(tu));
memset(vis,0,sizeof(vis));
memset(dis,inf,sizeof(dis));
for(int i = 1; i <= n; ++i)
{
scanf("%lf%lf",&x[i],&y[i]);
}
for(int i = 1; i <= n; ++i)
{
for(int j = i+1; j <= n; ++j)
{
tu[i][j] = sqrt((x[j]-x[i])*(x[j]-x[i])+(y[j]-y[i])*(y[j]-y[i]));
tu[j][i] = tu[i][j];
}
}
double res = prim();
printf("%.2f\n",res);
}
return 0;
}
欢迎指出错误qwq