问题描述
http://hihocoder.com/problemset/problem/1097?sid=773144
算法描述
首先我想证明一个结论:对于城市i(i≠1),如果i与城市1的距离不超过其他任何城市j(j≠1)与城市1的距离,那么(1, i)这一条边一定存在于某一棵最小生成树中。”
使用这个结论,我们可以得到prime算法。
如果我确定了(1, i)这条边一定存在于某一棵最小生成树中,那么我仿照Dijstra算法的思想,将1和i合并为一个点,那么问题是不是就变成了求剩下的N-2个点和这个点的最小生成树。
这里注意,在实现时维护一个当前树到未加入树的节点之间最小距离。不能每次重新算,否则会是O( n3 )复杂度。
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
enum {maxn = 1024};
int G[maxn][maxn];
int N;
int all = 0;
bool chose[maxn];
vector<int> treeNode;
int main()
{
//freopen("in.txt", "r", stdin);
memset(chose, 0, sizeof(chose));
scanf("%d", &N);
for (int i=0; i< N; i++)
for (int j = 0; j<N; j++)
scanf("%d", &G[i][j]);
chose[0] = true;
all = 0;
//treeNode.push_back(0);
// O(N^3) TLE
/* for (int i=1; i< N; i++)
{
int Min = 1<<30;
int MinNode = -1;
for (int j=0; j<treeNode.size(); j++ )
{
int node = treeNode[j];
for (int k=0; k< N; k++)
if (!chose[k] && G[node][k] < Min)
{
Min = G[node][k];
MinNode = k;
}
}
treeNode.push_back(MinNode);
chose[MinNode] = true;
all += Min;
}*/
// O(N^2);
int s = 0;
for (int i=1; i< N; i++)
{
int t= -1;
for (int j=0; j<N; j++ )
{
if (!chose[j]){
if (G[s][j] < G[0][j]) G[0][j] = G[s][j];
if (t<0 || G[0][t] > G[0][j]) t = j;
}
}
s = t;
chose[t] = true;
all += G[0][s];
}
printf("%d\n", all);
return 0;
}