思路:map+prim
map 用count(),find()方法判断键值是否存在。
这里有三篇文章可看看:
http://www.360doc.com/content/13/0912/18/3373961_314006267.shtml
http://www.cppblog.com/09212744/archive/2010/06/19/118235.html
http://blog.csdn.net/iaccepted/article/details/8554303
prim:
原理:每次连出该集合到其他所有点的最短边保证生成树的边权总和最小
1. 首先随便选一个点加入集合
2. 用该点的所有边去刷新到其他点的最短路
3. 找出最短路中最短的一条连接(且该点未被加入集合)
4. 用该点去刷新到其他点的最短路
5 重复以上操作n-1次
6 最小生成树的代价就是连接的所有边的权值之和
code:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <map>
using namespace std;
const int MAX_ = 50;
const int INF = 0x7fffffff;
map<string,int>exh;
int mp[MAX_][MAX_], d[MAX_];
bool vis[MAX_];
int prim(int start, int cnt){
for(int i = 0; i < cnt; ++i){
d[i] = INF;
vis[i] = 0;
}
d[start] = 0;
int k = start, ans = 0;
for(int i = 0; i < cnt; ++i){
int mini = INF;
for(int j = 0; j < cnt; ++j){
if(!vis[j] && d[j] < mini){
mini = d[j];
k = j;
}
}
vis[k] = 1;
ans += mini;
for(int i = 0; i < cnt; ++i){
if(!vis[i] && mp[k][i] && d[i] > mp[k][i]){
d[i] = mp[k][i];
}
}
}
return ans;
}
int main() {
//freopen("f:\\out.txt","w",stdout);
int n, l, x, ans, m, cap, cnt;
string str, s;
while(cin>>n && n) {
exh.clear();
cnt = 0;
memset(mp,0,sizeof(mp));
while(--n) {
cin>>str>>m;
if(exh.count(str) == 0)exh[str] = cnt++;
while(m--) {
cin>>s>>cap;
if(exh.count(s) == 0)exh[s] = cnt++;
mp[exh[str]][exh[s]] = mp[exh[s]][exh[str]] = cap;
}
}
cout<<prim(0,cnt)<<endl;
}
return 0;
}