最小生成樹(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

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