POJ 1251 - Jungle Roads
题意:第一行给出点的个数n,接下来n-1行描述它们之间的路径及长度。求连通所有点的最小花费。
思路:最小生成树模版题。
方法一,kruscal算法,不断找最小花费的路径,若不会与已选的路径构成环,则加入ans中,否则跳过这条边。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=30;
struct Edge{
int from, to;
int w;
}edge[N*N];
Edge ans[N*N];
int father[N];
int tol, cnt;
void add_edge(int u, int v, int w)
{
edge[tol].from=u;
edge[tol].to=v;
edge[tol].w=w;
tol++;
}
bool cmp(Edge a, Edge b)
{
if(a.w!=b.w) return a.w < b.w;
if(a.from != b.from) return a.from < b.from;
return a.to < b.to;
}
int find(int x)
{
if(father[x] == -1) return x;
return father[x]=find(father[x]);
}
void kruscal()
{
memset(father,-1,sizeof(father));
cnt=0;//加入最小生成树的边数
for(int k=0;k<tol;k++){
int u=edge[k].from;
int v=edge[k].to;
u=find(u); v=find(v);
if(u!=v){
ans[cnt++]=edge[k];
father[u]=v;
}
}
}
void init()
{
tol=0; cnt=0;
memset(edge,0,sizeof(edge));
}
int main()
{
int k, dis, n;
char x, y;
while(cin >> n && n){
init();
for(int i=1;i<n;i++){
cin >> x >> k;
while(k--){
cin >> y >> dis;
add_edge(x-'A', y-'A', dis);
add_edge(y-'A', x-'A', dis);
}
}
sort(edge,edge+tol,cmp1);
kruscal();
int res = 0;
for(int i=0;i<cnt;i++)
res+=ans[i].w;
cout << res << endl;
}
return 0;
}
另一种Prim算法类似于bfs,每次找和已选点连通的路径中的最小值,把这个点加入到已选的点集中,直到所有的点都在集合里。懒得写了,套了别人的模版,AC代码如下:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAX=30;
const int INF=200;
int graph[MAX][MAX] ;
bool visited[MAX];
int prim(int n)
{
int lowCost[MAX] ;
for(int i = 1 ; i <= n ; ++i)
{
lowCost[i] = graph[1][i] ;
}
memset(visited,false,sizeof(visited)) ;
visited[1] = true ;
lowCost[0] = INF ;
int sum = 0 ;
for(int i = 1 ; i < n ; ++i)
{
int index = 0 ;
for(int j = 1 ; j <= n ; ++j)
{
if(!visited[j] && lowCost[index]>lowCost[j])
{
index = j ;
}
}
if(index == 0)
break ;
sum += lowCost[index] ;
visited[index] = true ;
for(int j = 1 ; j <= n ; ++j)
{
if(!visited[j] && lowCost[j]>graph[index][j])
{
lowCost[j] = graph[index][j] ;
}
}
}
return sum ;
}
void init()
{
for(int i = 0 ; i < MAX ; ++i)
for(int j = 0 ; j < MAX ; ++j)
graph[i][j] = INF ;
}
int main()
{
int k, dis, n;
char x, y;
while(cin >> n && n){
init();
for(int i=1;i<n;i++){
cin >> x >> k;
while(k--){
cin >> y >> dis;
int a=x-'A'+1;
int b=y-'A'+1;
if(graph[a][b]>dis)
graph[a][b]=graph[b][a]=dis;
}
}
cout << prim(n) << endl;
}
return 0;
}