LA 6540 Fibonacci Tree
题意:
给出一个\(n\)个点\(m\)条边的无向图,每条边的颜色为黑色或者白色。问是否存在一颗生成树使得树上白边的数量为斐波那契数。
分析:
按边的颜色给边排个序,找出白边数量最多的生成树和白边数量最少的生成树。
从白边最少到白边最多的过程中,树上白边的数量是连续变换的。(这个结论不太会证)
所以如果这个区间中有斐波那契数那么答案就是存在
注意要判断一下原图是否连通
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 100000 + 10;
int n, m;
struct Edge
{
int u, v, c;
bool operator < (const Edge& e) const {
return c > e.c;
}
}edges[maxn];
int pa[maxn];
int findset(int x) { return x == pa[x] ? x : pa[x] = findset(pa[x]); }
int fib[100];
int main() {
fib[1] = 1; fib[2] = 2;
for(int i = 3; i <= 25; i++) fib[i] = fib[i - 1] + fib[i - 2];
int T; scanf("%d", &T);
for(int kase = 1; kase <= T; kase++) {
scanf("%d%d", &n, &m);
for(int i = 0; i < m; i++) {
scanf("%d%d%d", &edges[i].u, &edges[i].v, &edges[i].c);
}
sort(edges, edges + m);
for(int i = 1; i <= n; i++) pa[i] = i;
int cc = n, white1 = 0;
for(int i = 0; i < m && cc > 1; i++) {
Edge& e = edges[i];
int pu = findset(e.u), pv = findset(e.v);
if(pu == pv) continue;
cc--;
pa[pu] = pv;
if(e.c == 1) white1++;
}
if(cc > 1) { printf("Case #%d: No\n", kase); continue; }
for(int i = 1; i <= n; i++) pa[i] = i;
cc = n;
int white2 = 0;
for(int i = m - 1; i >= 0 && cc > 1; i--) {
Edge& e = edges[i];
int pu = findset(e.u), pv = findset(e.v);
if(pu == pv) continue;
cc--;
pa[pu] = pv;
if(e.c == 1) white2++;
}
//printf("%d %d\n", white2, white1);
bool ok = false;
for(int i = 1; i <= 24; i++) if(white2 <= fib[i] && fib[i] <= white1) {
ok = true; break;
}
printf("Case #%d: %s\n", kase, ok ? "Yes" : "No");
}
return 0;
}