题意:有n个点,要在他们之间搭建公路,知道一些点之间搭建公路的代价,求使所以点可以相互到达的最小代价(无向图、无环)。
思路一:Kruskal算法,先将建造路的代价由小到大排序,尽量取最小代价的点(如果取某条路后形成了环,没有增加连接的点,浪费,应舍弃)。
#include
#include
int loop[30]; //用于确定点的集合
struct Line
{
int dist, a, b;
}line[100];
int comp(const void *a, const void *b)
{
return (*(Line *)a).dist - (*(Line *)b).dist;
}
int find(int i) //确定某点所在的集合(的代表元)
{
if(loop[i] == i) return i;
return find(loop[i]);
}
int main()
{
#ifdef LOCAL
freopen("data.in", "r", stdin);
#endif
int n, k, num, ans, road, dist;
char l, r;
int i, j, x, y;
while(scanf("%d", &n) != EOF && n)
{
num = 0; ans = 0; road = 0;
for(i = 0; i < n - 1; i++)
{
scanf(" %c%d", &l, &k);
for(j = 0; j < k; j++)
{
scanf(" %c%d", &r, &dist);
line[num].dist = dist;
line[num].a = l - 'A';
line[num].b = r - 'A';
num++;
}
loop[i] = i; //起始时各点在一个只含自己的集合中
}
loop[i] = i;
qsort(line, num, sizeof(line[0]), comp);
for(i = 0; i < num; i++)
{
//printf("%d%c%c\n",line[i].dist, line[i].a+'A', line[i].b+'B');
//确定两个点分别属于的集合(的代表元)
x = find(loop[line[i].a]);
y = find(loop[line[i].b]);
if(x != y) //所属集合不同,在两点间增加路不会形成环
{
ans += line[i].dist;
loop[y] = x; //将两点相连,之后合并同两点所属集合
road++;
if(road == n - 1) break;
}
}
printf("%d\n", ans);
}
return 0;
}
思路二:Prim算法。
#include
#include
int dist[30][30], vis[30], mincost[30];
int n, ans;
int min(int a, int b)
{
if(a < b || b == 0)return a;
else return b;
}
int prim()
{
for(int u = 0; u < n; u++)//初始化最短路径
{
mincost[u] = 100000;
vis[u] = 0;
}
mincost[0] = 0;
int ans = 0;
while(1)
{
int v = -1;
for(int u = 0; u < n; u++)
{
if(!vis[u] && (v == -1 || mincost[u] < mincost[v]))
//在未连接的点中找路径最短的点(v=-1时未找到未连接的点)
v = u;
}
if(v == -1) break; //找不到未连接的点,即完成最小生成树
vis[v] = 1; //标记新加入的点
ans += mincost[v]; //统计连接点v后的最小路径长度
//printf("v=%d, mincost=%d\n", v, mincost[v]);
for(int u = 0; u < n; u++) //在连接了v点的条件下更新最短路径
{
mincost[u] = min(mincost[u], dist[v][u]);
}
}
return ans;
}
int main()
{
#ifdef LOCAL
freopen("data.in", "r", stdin);
#endif
char a, c;
int b, d;
while(scanf("%d", &n) != EOF && n)
{
memset(dist, 0, sizeof(dist));
memset(vis, 0, sizeof(vis));
for(int i = 0; i < n - 1; i++)
{
scanf(" %c%d", &a, &b);
for(int j = 0; j < b ;j++)
{
scanf(" %c%d", &c, &d);
dist[a - 'A'][c - 'A'] = dist[c - 'A'][a - 'A'] = d;
}
}
/*for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
printf("%2d ", dist[i][j]);
printf("\n");
}
*/
printf("%d\n", prim());
}
return 0;
}