题目链接: vjudge
题意
简单的最小生成树问题
输入
(最多100次询问)对于每次询问: 第一行给出店铺数量n; 接下来第二行到第n+1行, 给出当前店铺名称a ,与之直接相连的店铺的道路数k ,之后k组数据表示 与a相连的店铺名称和他们之间的道路维护费用 (多组数据输入,当店铺数量为0时,输入结束) 1 < n < 27, 0 <= k <= 15
输出
最小生成树权值之和
输入样例
9
A 2 B 12 I 25
B 3 C 10 H 40 I 8
C 2 D 18 G 55
D 1 E 44
E 2 F 60 G 38
F 0
G 1 H 35
H 1 I 35
3
A 2 B 10 C 40
B 1 C 20
0
输出样例
216
30
解题思路
真没啥可说的,简单的最小生成树,可以用prim和kruscal。就当是复习两个算法了。
可以学习的点:
- 对于输入的处理
scanf("%s %d", c, &m);
因为scanf()会把空格当作分隔符,所以非常适合这样处理输入。
AC代码(Prim)
#include <cstdio>
#include <vector>
#include <cstring>
#define Max 0x3f3f3f3f
using namespace std;
int map[30][30];
int dis[30];
bool vis[30];
int n;
int min(int a, int b)
{
if (a < b)
return a;
return b;
}
int prim()
{
int ans=0;
memset(vis, false, sizeof vis);
dis[1] = 0;
vis[1] = true;
for (int i = 2; i <= n; i++)
{
dis[i] = min(map[1][i], dis[i]);
}
int temp ;
int k ;
for (int i = 2; i <= n; i++)
{
temp = Max;
k = -1;
for (int j = 2; j <= n; j++)
{
if (!vis[j] && dis[j] < temp)
{
k = j;
temp = dis[j];
}
}
// 图不连通
if (k == -1)
return Max;
vis[k] = true;
ans += dis[k];
if (k != -1)
{
for (int j = 2; j <= n; j++)
{
if (!vis[j])
dis[j] = min(map[k][j], dis[j]);
}
}
}
return ans;
}
int main()
{
while (scanf("%d", &n) && n != 0)
{
for (int i = 1; i <= n; i++)
{
map[i][i] = 0;
dis[i] = Max;
for (int j = 1; j < i; j++)
{
map[i][j] = map[j][i] = Max;
}
}
for (int i = 0; i < n - 1; i++)
{
char c[10];
int source, target, m;
scanf("%s %d", c, &m);
source = c[0] - 'A' + 1;
for (int j = 0; j < m; j++)
{
int weight;
scanf("%s %d", c, &weight);
target = c[0] - 'A' + 1;
if (map[source][target] > weight)
{
map[source][target] = map[target][source] = weight;
}
}
}
printf("%d\n", prim());
}
return 0;
}
AC代码(kruscal)
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;
int pre[30];
int n;
typedef struct
{
int source, target, weight;
} point;
class mycompare
{
public:
bool operator()(point a, point b)
{
return a.weight < b.weight;
}
};
multiset<point, mycompare> map;
int find(int x)
{
if (pre[x] == x)
return x;
return pre[x] = find(pre[x]);
}
bool isSame(int x, int y)
{
return find(x) == find(y);
}
void initpre()
{
for (int i = 1; i <30; i++)
{
pre[i] = i;
}
}
int kruskal()
{
int rec = 0;
int ans = 0;
while (!map.empty())
{
if (rec == n - 1)
break; // 直到选用了n-1条边之后退出循环
multiset<point, mycompare>::const_iterator buf = map.begin();
if (!isSame((*buf).source, (*buf).target))
{
pre[find((*buf).target)] =find((*buf).source) ;
ans += (*buf).weight;
rec++;
}
map.erase(buf);
}
return ans;
}
int main(void)
{
while (~scanf("%d", &n))
{
map.clear();
if (n == 0)
break;
initpre(); // 初始化
char str[10];
int a, b;
for (int i = 1; i < n; i++)
{
scanf("%s %d", str, &a);
int u = str[0] - 'A' + 1;
for (int i = 1; i <= a; i++)
{
scanf("%s %d", str, &b);
int v = str[0] - 'A' + 1;
point buf;
buf.source = u;
buf.target = v;
buf.weight = b;
map.insert(buf);
}
}
printf("%d\n", kruskal());
}
return 0;
}