最小生成树(2)——prim算法//HDU1223+SDNU1229

第一行国际惯例咕咕咕。

第二行——欠的东西总是要还的——来自一个上次写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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章