在我的最小生成樹的Prim算法的模板 基礎上增加一個vis數組用於區分節點是否已加入集合T中。這裡不能使用節點的min_dis為0作為該節點是否加入T中,因為題目中給出了已經相連的邊,而我們將其權值設為了0,需要另加數組判斷。
另一個注意點是這裡Prim不一定需要執行循環N-1次,同樣因為有邊權初始化為0。及時終止循環可以稍微提高效率。
我的解題代碼如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <string>
#include <algorithm>
using namespace std;
#define Distance double
#define INF 1000000
#define MAXN 750
double x[MAXN],y[MAXN];
Distance dis[MAXN][MAXN];
Distance min_dis[MAXN];
//int nearest_v[MAXN];
int vis[MAXN];
Distance Prim(int v0, int N)
{
//init
for(int i=0; i<N; i++)
{
min_dis[i] = dis[i][v0];
// nearest_v[i] = v0;
}
min_dis[v0] = 0;
memset(vis,0,sizeof(vis));
vis[v0] = 1;
Distance total_dis = 0;
for(int k=1; k<N; k++)
{
Distance md = INF;
int nv = v0;
for(int i=0; i<N; i++) if(!vis[i])
{
if(md > min_dis[i])
{
md = min_dis[i];
nv = i;
}
}
total_dis += md;
min_dis[nv] = 0;
vis[nv] = 1;
for(int i=0; i<N; i++) if(!vis[i])
{
if(min_dis[i] > dis[i][nv])
{
min_dis[i] = dis[i][nv];
// nearest_v[i] = nv;
}
}
int ok = 0;
for(int i=0; i<N; i++) if(min_dis[i]!=0) { ok=1; break; }
if(!ok) break;
}
return total_dis;
}
int main()
{
int N,M;
while(cin >> N)
{
for(int i=0; i<N; i++)
{
scanf("%lf %lf",&x[i],&y[i]);
for(int j=0; j<=i; j++)
dis[i][j]=dis[j][i]=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
}
cin >> M;
int na,nb;
for(int i=0; i<M; i++)
{
scanf("%d %d",&na,&nb);
dis[na-1][nb-1]=dis[nb-1][na-1]=0;
}
printf("%.2lf\n", Prim(0,N));
}
return 0;
}