现有学校宿舍区之间要铺设光纤建设网络,在施工预算的统计数据表中,列出了有可能建设光缆的若干条管线的成本,求使每栋楼都能够接入校园网且使管网建设费用成本最低。
输入:
第一行数据包括楼宇的数目正整数N(≤1000)和候选管网数目M(≤3N);
随后的M行对应M条线路,每行给出3个正整数,分别是该条线路直接连通的两个楼宇的编号以及预算成本(为简单起见,城镇从1到N编号)。
输出:
输出建设楼楼通需要的最低成本。如果输入数据不足以保证畅通,则输出−1,表示需要建设更多的通路。
思路:
1)首先要建立网络楼连通之间的图
2)对节点之间路径的加权赋值
3)每次都选择路径最短的一个环,同时要判断是否成环,这就是kruskal克鲁斯卡尔算法,
我们借助并查集(并查集)来判断是否成环:即对于某个新选择的环,我们需要判断的就是新选择的这个节点是否与已选择的节点成环,成环的判断就是这两个节点的头(即通过并查集找到头)是否相同,不相同才可以选择。
这是对并查集的代码:
void init()
{
for (int i = 0; i <= n; i++)
{
tree[i] = i;
}
}
int find(int t)
{
if (tree[t] == t)
{
return t;
}
else
{
return tree[t] = find(tree[t]);
}
}
完整代码:
#include<iostream>
#include<algorithm>
using namespace std;
struct node {
int x;
int y;
int cost;
};
node road[5000];
struct cmp
{
bool operator()(const node& A, const node& B) const
{
return A.cost < B.cost;
}
};
int tree[1000];
int n, m;
void init()
{
for (int i = 0; i <= n; i++)
{
tree[i] = i;
}
}
int find(int t)
{
if (tree[t] == t)
{
return t;
}
else
{
return tree[t] = find(tree[t]);
}
}
int judge(int x, int y)
{
int a = find(x);
int b = find(y);
if(a != b)
{
tree[a] = b;
return 1;
}
else
{
return 0;
}
}
void kruskal()
{
int side = 0;
int sum = 0;
init();
sort(road, road + m, cmp());
for (int i = 0; i < m; i++)
{
if (judge(road[i].x, road[i].y))
{
side++;
sum += road[i].cost;
}
if (side == n - 1)
{
break;
}
}
if (side != n - 1)
{
cout << "-1" << endl;
}
else
{
cout << sum << endl;
}
}
int main()
{
cin >> n >> m;
for (int i = 0; i < m; i++)
{
cin >> road[i].x >> road[i].y >> road[i].cost;
}
kruskal();
return 0;
}
思考:
并不是所有图的问题都是一样的解决办法,根据题目所需要求的东西进行设计数据结构。
如要建立无向图以及遍历等,就需要邻接表、邻接矩阵、十字链表(有向图)等方式进行完整的建立结构,邻接表结构就需要信息:c(端点信息)、visit(遍历)、chain(邻接表水平)、cnum(邻接表下标)
但如本题重点关注的是环,以及环的两端对应的节点,因此本题对环结构化,除cost信息外,取x,y为两个端点即可。重点为kruskal克鲁斯卡尔算法&&并查集对是否成环的初始化和检查这个结构。