原题链接:
https://vjudge.net/problem/HDU-4786
AC代码:
#include <algorithm>
#include <bits/stdc++.h>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
const int INF = 0x3fffffff;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e6 + 10;
void __init__() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
} //head
int n, m;
int fa[maxn];
bool fib[maxn];
int maxx, minn;
struct Edge {
int u, v, w;
} edge[maxn];
//最大生成
int cmp1(Edge a, Edge b) {
return a.w > b.w;
}
//最小生成
int cmp2(Edge a, Edge b) {
return a.w < b.w;
}
//计算斐波那契数
void getfib() {
memset(fib, 0, sizeof(fib));
ll a = 1, b = 1;
fib[1] = 1;
while (b < maxn) {
ll temp = a + b;
a = b;
b = temp;
fib[b] = 1;
}
}
//并查集操作
int find(int x) {
if (x == fa[x]) {
return x;
}
return fa[x] = find(fa[x]);
}
void uni(int x, int y) {
int xt = find(x);
int yt = find(y);
if (xt != yt) {
fa[xt] = yt;
}
}
//建树
int kruskal() {
for (int i = 1; i <= n; i++) {
fa[i] = i;
}
Edge now;
int sum = 0;
for (int i = 1; i <= m; i++) {
now = edge[i];
if (find(now.u) != find(now.v)) {
uni(now.u, now.v);
sum += now.w;
}
}
return sum;
}
int main() {
// __init__();
getfib();
int t;
cin >> t;
int cases = 1;
while (t--) {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w);
}
//构建最小生成树并计算加权和
sort(edge + 1, edge + m + 1, cmp1);
maxx = kruskal();
int cnt = 0;
for (int i = 1; i <= n; i++) {
if (fa[i] == i) {
cnt++;
if (cnt > 1)
break;
}
}
if (cnt > 1) {
printf("Case #%d: No\n", cases++);
continue;
}
//构建最大生成树并计算加权和
sort(edge + 1, edge + m + 1, cmp2);
minn = kruskal();
cnt = 0;
for (int i = 1; i <= n; i++) {
if (fa[i] == i) {
cnt++;
if (cnt > 1)
break;
}
}
if (cnt > 1) {
printf("Case #%d: No\n", cases++);
continue;
}
//必然存在任何权值介于最小生成树与最大生成树权值之间的树
int flag = 0;
for (int i = minn; i <= maxx; i++) {
if (fib[i]) {
flag = 1;
break;
}
}
if (flag)
printf("Case #%d: Yes\n", cases++);
else
printf("Case #%d: No\n", cases++);
}
return 0;
}
日常补题,参考的网上大佬们的代码,讲道理这题一开始一点思路都没有,看了网上的题解才知道有这么一说:
图的最大生成树和最小生成树的边权和分别为max, min,那么,一定可以构造出合法的生成树,使得其边权和在区间[min, max]
我们应用并查集分别构建最小/最大生成树,计算器边权和,在范围内判断是否有斐波那契数在其中即可