http://acm.hdu.edu.cn/showproblem.php?pid=4786
Fibonacci Tree
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 49 Accepted Submission(s): 26
Consider a bidirectional graph G with N vertices and M edges. All edges are painted into either white or black. Can we find a Spanning Tree with some positive Fibonacci number of white edges?
(Fibonacci number is defined as 1, 2, 3, 5, 8, ... )
思路:想法題,感覺成都的題想法很重要啊。。。
首先判斷整個圖是否連通,若不連通直接輸出No,都不連通了當然生成樹就無從說起了嘛。
接下來僅討論白邊,黑邊不看,看最多能加入多少條白邊,使得不存在環。這樣我們得到了能加入白邊的最大值max。(就是所有生成樹裏白邊數量的最大值)。
接下來同理僅討論黑邊,這樣我們可以得到可加入白邊的最小值min,(也可以認爲是所有生成樹中白邊的最小值)。
然後我們只要判斷這兩個值之間是否存在斐波那契數就行了。
爲什麼呢?這裏說明一下,
我們等於是要證明對於所有在min和max之間的白邊數我們都能夠達到。
考慮從最小的min開始,我總可以找到一條黑邊,使得將它去掉在補上一條白邊保持圖聯通。爲什麼呢,如果在某一個狀態(設白邊數爲x)下,不存在一條黑邊可以被白邊代替,那麼現在我們把所有黑邊去掉,剩下x條白邊,那我們知道,x一定等於max,因爲若x<max,那麼我們在算max的那個步驟中,現將這x條白邊加入,還可以在加入max-x條白邊使得不存在環,那麼這與沒有一條黑邊可以被白邊代替矛盾,所以這就證明了從min到max我都可以達到。
說的有點亂,感覺自己想想還是能能明白的吧。下面就是代碼了,很好理解應該。
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#define maxn 100010
using namespace std;
int f[maxn],febo[50];
int n,m;
struct edge
{
int u,v,c;
}e[maxn];
int find(int x)
{
return f[x]==x?x:f[x]=find(f[x]);
}
int solve(int col)
{
int num=0;
for(int i=1;i<=n;i++)f[i]=i;
for(int i=1;i<=m;i++)
{
if(e[i].c!=col)
{
int x=find(e[i].u),y=find(e[i].v);
if(x!=y)
{
f[x]=y;
num++;
}
}
}
return num;
}
int main()
{
freopen("dd.txt","r",stdin);
febo[0]=1,febo[1]=2;
int num;
for(num=2;;num++)
{
febo[num]=febo[num-1]+febo[num-2];
if(febo[num]>100000)
break;
}
int ncase,T=0;
scanf("%d",&ncase);
while(ncase--)
{
printf("Case #%d: ",++T);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].c);
int tmp,mi,ma,tru=0;
tmp=solve(2);
if(tmp!=n-1)
{
printf("No\n");
continue;
}
ma=solve(0);
mi=n-1-solve(1);
for(int i=0;i<num;i++)
{
if(febo[i]>=mi&&febo[i]<=ma)
{
tru=1;
break;
}
}
if(tru)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}