链接:http://cstest.scu.edu.cn/soj/problem.action?id=3366
题目大意:要建井,每个地方都要有,可以选择直接在这里挖井,也可以选择从其他地方已经有井的地方建一条路到这个地方来。
有一段时间没有写过最小生成树了,感觉都有一点快要忘记了的感觉。。。。
这道题之前没有过,借鉴了一下别人的思想。。发现真的好简单。。。而且这种方法在以前使用过,这回居然没有想出来,,要反思一下了。。。感觉跟之前那个只是换了个描述而已····
思路:既然可以挖井,那么也就意味着可以从任意一个井开始挖,甚至还可以每个都用挖的而不建路,这样不方便求最小生成树,但是可以自己设立一个总的起点,这个总起点到各个水井的权值就是挖井所需要的花费,这样我们就转化成了只有一个开始的点,从这个起点出去求最小生成树就可以啦。也能保证至少有一个井是挖出来的
还有一个感觉是一个学长写的题解:http://twocoldzcainiao.sinaapp.com/?p=152
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 309
struct node
{
int u,v,w;
}edge[M*M];
int p[M];
int k;
int ans;
int cmp(node a,node b)
{
return a.w < b.w;
}
int find(int x)
{
return x==p[x]?x:p[x]=find(p[x]);
}
void kruskal()
{
for(int i = 0;i < k;i++)
{
int x = find(edge[i].u); //找出根节点
int y = find(edge[i].v);
if(x!=y) //如果根节点不相同(即不在同一个集合之中)就加上这条边
{
ans += edge[i].w;
p[x] = y; //合并节点。
}
}
}
int main()
{
int n;
while(scanf("%d",&n)==1)
{
k = 0;
ans = 0;
for(int i = 0;i <= n;i++)
p[i] = i;
for(int i = 1;i <= n;i++)
{
int a;
scanf("%d",&a);
edge[k].u = 0;
edge[k].v = i;
edge[k++].w = a;
}
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= n;j++)
{
int a;
scanf("%d",&a);
if(i==j) continue;
edge[k].u = i;
edge[k].v = j;
edge[k++].w = a;
}
}
sort(edge,edge+k,cmp);
kruskal();
printf("%d\n",ans);
}
return 0;
}