2020.10.16第二次每日一题
题目:通电
解决的方法:
要让所有的村庄连在一起,并且花费最小,标准的最小生成树问题
什么是最小生成树呢?网上搜都能搜到。常用的最小生成树算法一般是两个:
1.Prim算法:不断加点的方式;2.Kruskal算法:不断加边的方式,这里先给出Kruskal的算法。
Kruskal算法
首先就是存点和边,然后我们使用到的数组尽量在主函数外面开,在里面开直接MLE了
const int MAX = 1005;
int a[MAX], parent[MAX];
int n;
struct edge
{
int start;
int end;
int cost;
} edges[MAX * (MAX - 1) / 2];
struct node
{
int x;
int y;
int h;
} Node[MAX];
然后定义的是边权值是如何计算的,还有并查集的三个函数
//计算边的权值
double cost(node a,node b)
{
double xx=a.x-b.x;
double yy=a.y-a.y;
double hh=a.h-b.h;
return sqrt(xx*xx+ yy*yy) + hh*hh;
}
int get_root(int a)
{
if (parent[a] != a)
{
parent[a] = get_root(parent[a]);
}
return parent[a];
}
void Merge(int a, int b)
{
parent[get_root(a)] = get_root(b);
}
bool Query(int a, int b)
{
return get_root(a) == get_root(b);
}
接下来是主函数
int main()
{
int n, num = 0;
cin >> n;
initial(n);
for (int i = 0; i < n; i++)
{
cin >> Node[i].x >> Node[i].y >> Node[i].h;
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n && j != i; j++)
{
edges[num].start = i;
edges[num].end = j;
edges[num].cost = cost(Node[i], Node[j]);
num++;
}
}
sort(edges, edges + num);
double sum = 0.0;
int count=0;
for (int k = 0; k < num; k++)
{
/*if (!Query(edges[k].start, edges[k].end))
{
Merge(edges[k].start, edges[k].end);
sum+=edges[k].cost;
count++;
}
*/
int start = edges[k].start;
int end = edges[k].end;
if(get_root(start) != get_root(end))
{
count++;
sum+=edges[k].cost;
if(count == n-1)
{
break;
}
}
}
cout<<setiosflags(ios::fixed)<<setprecision(2)<<sum<<endl;//C++中的保留小数的输出函数
return 0;
}
修改
感觉很好啊,功能都实现了,应该可以一次性通过啊,结果经历了漫长的修改之路
开始报错是,sort函数使用错误,因为我们是对结构体数组进行排序,所以要自己写一个比较的函数,告诉电脑该如何去排序
bool cmp(edge a,edge b)
{
rerturn a.cost < b.cost;
}
//主函数里也需要修改
sort(edges, edges + num , cmp);
发现还是不对哇,发现如果用函数去调用会发生爆栈,直接 MLE了,只好去主函数里修改了一下,怎么办呢?我们就不调用那几个函数了,直接用语句去替换
if(get_root(start) != get_root(end))
{
count++;
sum+=edges[k].cost;
if(count == n-1)
{
break;
}
}
结果发现还是不太对,搞死搞不出来,结果竟然是14,样例都不对
从头到尾检查一遍,发现原来困扰了1个小时的问题竟然是这里
double cost(node a,node b)
{
double xx=a.x-b.x;
double yy=a.y-a.y;//就是这
double hh=a.h-b.h;
return sqrt(xx*xx+ yy*yy) + hh*hh;
}
好吧,我尽力了,这就是刷题的快乐,成功的那一刻喜悦之情是溢于言表的、
完整代码
#include <iostream>
#include <cmath>
#include <algorithm>
#include <bits/stdc++.h>
#include <iomanip>
using namespace std;
const int MAX = 1005;
int a[MAX], parent[MAX];
int n;
struct edge
{
int start;
int end;
double cost;
} edges[MAX * (MAX - 1) / 2];
struct node
{
int x;
int y;
int h;
} Node[MAX];
double cost(node a,node b)
{
double xx=a.x-b.x;
double yy=a.y-a.y;
double hh=a.h-b.h;
return sqrt(xx*xx+ yy*yy) + hh*hh;
}
void initial(int n)
{
for (int i = 1; i <= n; i++)
{
parent[i] = i;
}
}
int get_root(int a)
{
if (parent[a] != a)
{
parent[a] = get_root(parent[a]);
}
return parent[a];
}
void Merge(int a, int b)
{
parent[get_root(a)] = get_root(b);
}
bool Query(int a, int b)
{
return get_root(a) == get_root(b);
}
bool cmp(edge a,edge b)
{
return a.cost<b.cost;
}
int main()
{
int n, num = 0;
cin >> n;
initial(n);
for (int i = 0; i < n; i++)
{
cin >> Node[i].x >> Node[i].y >> Node[i].h;
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n && j != i; j++)
{
edges[num].start = i;
edges[num].end = j;
edges[num].cost = cost(Node[i], Node[j]);
num++;
}
}
sort(edges, edges + num ,cmp);
double sum = 0.0;
int count=0;
for (int k = 0; k < num; k++)
{
/*if (!Query(edges[k].start, edges[k].end))
{
Merge(edges[k].start, edges[k].end);
sum+=edges[k].cost;
count++;
}
*/
int start = edges[k].start;
int end = edges[k].end;
if(get_root(start) != get_root(end))
{
count++;
sum+=edges[k].cost;
if(count == n-1)
{
break;
}
}
}
cout<<setiosflags(ios::fixed)<<setprecision(2)<<sum<<endl;
return 0;
}
昨天去紫金山实习去了,今天继续补题了…
近期预告:
线段树、树状数组、状压DP、Trie树、图论
如果大家有什么建议或者要求请后台留言
联系方式:shirandexiaowo@foxmail.com