第一行國際慣例咕咕咕。
第二行——欠的東西總是要還的——來自一個上次寫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