最小生成树模板
Kruskal
#include <stdio.h>
#include <iostream>
#include <math.h>
#include <algorithm>
#define scd2(a, b) scanf("%d %d", &a, &b)
#define scd3(a, b, c) scanf("%d %d %d", &a, &b, &c)
#define prd(a) printf("%d\n",a)
#define fr(a,b,c) for(int a=b;a<=c;a++)
using namespace std;
struct rec{
int a, b, c;
} edge[100100];
int fa[100100];
bool cmp(rec x, rec y){
return x.c < y.c;
}
int get(int x) {
if (x == fa[x]) return x;
return fa[x] = get(fa[x]);
}
int main(){
int n, m;
scd2(n, m);//
fr(i, 1, m){
scd3(edge[i].a, edge[i].b, edge[i].c);
}
//按照边权排序
sort(edge + 1, edge + m + 1, cmp);
//并查集初始化
fr(i, 1, n) fa[i] = i;
//kruskal
int ans = 0;
fr(i, 1, m){
int x = get(edge[i].a);
int y = get(edge[i].b);
if(x == y) continue;
fa[x] = y;
ans += edge[i].c;
}
prd(ans);
return 0;
}
Prim
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#define scd2(a,b) scanf("%d %d",&a,&b)
#define scd3(a,b,c) scanf("%d %d %d",&a,&b,&c)
#define prd(a) printf("%d\n",a)
#define fr(a,b,c) for(int a=b;a<=c;a++)
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
int a[3010][3010], d[3010], n, m;
bool v[3010];
void prim(){
mem(d, 0x3f);
mem(v, 0);
d[1] = 0;
fr(i, 1, n){
int x = 0;
fr(j, 1, n){
if(!v[j] && (x == 0 || d[j] < d[x])) x = j;
}
v[x] = 1;
fr(y, 1, n){
if(!v[y]) d[y] = min(d[y], a[x][y]);
}
}
}
int main(){
scd2(n, m);
mem(a, 0x3f);
fr(i, 1, n) a[i][i] = 0;
fr(i, 1, m){
int x, y, z;
scd3(x, y, z);
a[y][x] = a[x][y] = min(a[x][y], z);
}
prim();
int ans = 0;
fr(i, 2, n) ans += d[i];
prd(ans);
return 0;
}
A - Jungle Roads
题意:给出节点和距离,求最小生成树
题解:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
struct rec{
int a, b, c;
} edge[100100];
int fa[100100];
bool comp(rec x, rec y){
return x.c < y.c;
}
int get(int x){
int temp = x;
while(x != fa[x]) x = fa[x];
while(temp != fa[temp]){
int t_temp = temp;
temp = fa[temp];
fa[t_temp] = x;
}
return x;
}
int kruskal(int villagenum,int waynum){
}
int main(){
int t;
while(cin >> t){
if(t == 0) break;
int o = 0;
for(int i = 0; i < t - 1; i ++){
char ch1; cin >> ch1;
int temp1; cin >> temp1;
for(int j = 0; j < temp1; j ++){
char ch2; cin >> ch2;
edge[o].a = ch1 - 'A';
edge[o].b = ch2 - 'A';
cin >> edge[o].c;
o ++;
}
}
sort(edge, edge + o, comp); //结构体数组排序写法
for(int i = 0; i < t; i ++){
fa[i] = i;
}
int ans = 0;
for(int i = 0, j = 0; j < t - 1; i ++){
int v1 = edge[i].a;
int v2 = edge[i].b;
v1 = get(v1);
v2 = get(v2);
if(v1 != v2){
fa[v2] = v1;
j ++;
ans += edge[i].c;
}
}
cout << ans << endl;
}
return 0;
}
B - Networking
题意:给出点边的个数和各个边的长度,求最小生成树
题解:
#include <iostream>
#include <algorithm>
#include <stdio.h>
using namespace std;
struct rec{int x, y, z;} edge[500010];
int fa[100100], n, m, ans;
bool operator < (rec a, rec b){//用于sort排序
return a.z < b.z;
}
int get(int x){
if(x == fa[x]) return x;
return fa[x] = get(fa[x]);
}
int main(){
while(true){
cin >> n;
if(n == 0) break;
cin >> m;
if(m == 0){
cout << "0" << endl;
continue;
}
for(int i = 1; i <= m; i ++){
scanf("%d%d%d", &edge[i].x, &edge[i].y, &edge[i].z);
}
sort(edge + 1, edge + m + 1);//对权值进行排序
for(int i = 1;i <= n; i ++) fa[i] = i;
ans = 0;
for(int i = 1; i <= m; i ++){
int x = get(edge[i].x);
int y = get(edge[i].y);
if(x == y) continue;
fa[x] = y;
ans += edge[i].z;
}
cout << ans << endl;
}
return 0;
}
C - Building a Space Station
题意:给出多个空间球,求任意两个球圆心之间的距离,如果距离大于两个半径和,那么就是(距离 - 半径)和,要不然就是0,然后求最小生成树。
题解:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
struct rec{
int a;
int b;
double c;
} edge[100100];
int fa[100100];
struct Ball{
double x;
double y;
double z;
double r;
} ball[100100];
int cmp(rec x, rec y){
return x.c < y.c;
}
int get(int x){
if (x == fa[x]) return x;
return fa[x] = get(fa[x]);
}
int main(){
int t;
while(true){
cin >> t;
if(t == 0) break;
for(int i = 1; i <= t ; i ++){
fa[i] = i;
cin >> ball[i].x >> ball[i].y >> ball[i].z >> ball[i].r;
}
int o = 0;
double temp;
for(int i = 1; i <= t; i ++){
for(int j = i + 1; j <= t; j ++){
temp = sqrt((ball[i].x - ball[j].x)*(ball[i].x - ball[j].x) + (ball[i].y - ball[j].y)*(ball[i].y - ball[j].y) + (ball[i].z - ball[j].z)*(ball[i].z - ball[j].z));
temp -= (ball[i].r + ball[j].r);
if(temp < 0) temp = 0;
o ++;
edge[o].a = i;
edge[o].b = j;
edge[o].c = temp;
}
}
sort(edge + 1, edge + o + 1, cmp);
int flag = 1;
double ans = 0;
for(int i = 1; i <= o; i ++){
int x = get(edge[i].a);
int y = get(edge[i].b);
if(x != y){
fa[x] = y;
ans += edge[i].c;
flag ++;
if(flag == t) break;
}
}
printf("%.3lf\n", ans);
}
return 0;
}
D - Constructing Roads
题意:
题解:
E - Truck History
题意:
题解:
F - Arctic Network
题意:
题解:
G - Highways
题意:
题解:
H - Agri-Net
题意:
题解:
I - Borg Maze
题意:
题解:
J - The Unique MST
题意:
题解:
K - 还是畅通工程
这题和B题几乎一样
题意:
题解:
L - Jungle Roads
题意:
题解:
M - 畅通工程再续
题意:给出小岛的坐标,要求任意两个岛可以形成通路。若有小岛到其他任意小岛的距离小于10或大于1000则输出oh!
题解:
#include <stdio.h>
#include <iostream>
#include <math.h>
#include <algorithm>
using namespace std;
int x[110], y[110], fa[110], s;
struct rec{
int a, b;
double c;
} edge[10100];
bool cmp(rec x, rec y){
return x.c < y.c;
}
int get(int x) {
if (x == fa[x]) return x;
return fa[x] = get(fa[x]);
}
int main(){
ios::sync_with_stdio(false);
int t;
cin >> t;
while(t --){
int n, o = 0;
cin >> n;
for(int i = 1; i <= n; i ++){
cin >> x[i] >> y[i];
}
double temp;
for(int i = 1; i <= n; i ++){
for(int j = i + 1; j <= n; j ++){
temp = sqrt((double)((y[j] - y[i])*(y[j] - y[i]) + (x[j] - x[i])*(x[j] - x[i])));
if(temp >= 10 && temp <= 1000){
o ++;
edge[o].a = i;
edge[o].b = j;
edge[o].c = sqrt((double)((y[j] - y[i])*(y[j] - y[i]) + (x[j] - x[i])*(x[j] - x[i])));
}
}
}
//排序
sort(edge + 1, edge + o + 1, cmp);
//并查集
for(int i = 1; i <= n; i ++) fa[i] = i;
int flag = 0;
double ans = 0;
for (int i = 1; i <= o; i ++){
int x = get(edge[i].a);
int y = get(edge[i].b);
if(x != y){
fa[y] = x;
flag ++;
ans += edge[i].c;
}
}
if (flag == n - 1) printf("%.1f\n", ans * 100);
else cout << "oh!" << endl;
}
return 0;
}