题目大意:
给出一个图,其中最多有100000 个点,100000条边,对于每条边,要么是黑色,要么是白色,问是否能找到一个生成树,使得这个生成树的边中,白边的数量正好是Fibonacci数。
大致思路:
对于给出的图,首先若是没有生成树,则输出 No
若有生成树,则记白边边权值为1,黑边为0; 找出最小生成树,然后找出最大生成树
这样便得到了白边数量的两个临界值,由于白边的最小值是形成生成树当中不可缺少的白边(从Kruskal算法的排序选择边的过程也可看出来)这样,对于最少白边之外的白边都可以找到黑边来代替,换句话说,即使在原来的已经生成了最大生成树的图中,去掉某条生成树上的非必要白边(不在最小生成树中),都可以有相应的黑边来补充使得这个图重新形成生成树,这样,对于两个临界值之间的所有白边数,都可以找到对应的生成树,于是,只需要判断在这两个临界值之间是否有Fibonacci number即可
代码如下:
Result : Accepted Memory : 2188 KB Time : 437 ms
/*
* Author: Gatevin
* Created Time: 2014/7/9 20:41:16
* File Name: test.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define MAXN 100000
int V,E;
int u[MAXN + 10];
int v[MAXN + 10];
int w[MAXN + 10];
int r[MAXN + 10];
int f[MAXN + 10];
int Fibonacci[30];//Fibonacci[1] = 1, [2] = 2; [3] = 3; [4] = 5;.... [24] = 75025; [25] = 121393
int find(int i)
{
if(i != f[i])
{
f[i] = find(f[i]);
}
return f[i];
}
bool cmp1(const int & i, const int & j)
{
return w[i] < w[j];
}
bool cmp2(const int & i, const int & j)
{
return w[j] < w[i];
}
int Kruskal(int flag)
{
for(int i = 1; i <= V; i++)
{
f[i] = i;
}
for(int i = 1; i <= E; i++)
{
r[i] = i;
}
switch(flag)
{
case 1 : sort(r + 1, r + E + 1, cmp1); break;
case 2 : sort(r + 1, r + E + 1, cmp2); break;
}
int answer = 0;
int cnt = 0;
for(int i = 1; i <= E; i++)
{
int e = r[i];
int rx = find(u[e]);
int ry = find(v[e]);
if(rx != ry)
{
f[rx] = ry;
cnt++;
answer+= w[e];
}
}
if(cnt == V - 1)
{
return answer;
}
else
{
return 4;//Here 4 is not a Fibonacci number, so when there is no spanning tree, then in main fuction, program will output "No"
}
}
int main()
{
Fibonacci[1] = 1;
Fibonacci[2] = 2;
for(int i = 3; i <= 30; i++)
{
Fibonacci[i] = Fibonacci[i - 1] + Fibonacci[i - 2];
}
int T;
scanf("%d",&T);
for(int cas = 1; cas <= T; cas++)
{
scanf("%d %d", &V, &E);
for(int i = 1; i <= E; i++)
{
scanf("%d %d %d", &u[i], &v[i], &w[i]);
}
int tmp1 = Kruskal(1);//find the minimum number for white edges
int tmp2 = Kruskal(2);//find the maximum number for white edges
for(int i = 1; Fibonacci[i] <= tmp2; i++)
{
if(tmp1 <= Fibonacci[i] && Fibonacci[i] <= tmp2)
{
printf("Case #%d: Yes\n", cas);
goto nex;
}
}
printf("Case #%d: No\n", cas);
nex:;
}
return 0;
}