標籤:style blog color os sp for div on log
題意:
N個點,M條邊。每條邊串連兩個點u,v,且有一個權值c,c非零即一。
問能否將N個點形成一個產生樹,並且這棵樹的邊權值和是一個fibonacii數。 (fibonacii數=1,2,3,5,8 .... )
思路:
若可以產生一棵樹。則有最小產生樹和最大產生樹。假設已經產生了最小MST P 和最大MST Q。
將P更換一條邊可以得到另一棵產生樹,邊權和不是和P相等就是比P的邊權和大1。(因為邊值非零即一)。同理搞下去....一定可以得到Q。
所以P的邊權和到Q的邊權和之間的所有值都能得到。故判斷之間是否存在fibonacii數即可。
代碼:
struct node{ int u,v,c;}edge[100005];bool cmp(node a,node b){ return a.c<b.c;}int fa[100005];int T,n,m;int findFa(int x){ return fa[x]==x?x:fa[x]=findFa(fa[x]);}int kruskal1(){ rep(i,1,n) fa[i]=i; int res=0; rep(i,1,m){ int fx=findFa(edge[i].u); int fy=findFa(edge[i].v); if(fx!=fy){ fa[fx]=fy; res+=edge[i].c; } } int tx=findFa(1); rep(i,2,n) if(findFa(i)!=tx) return -1; return res;}int kruskal2(){ rep(i,1,n) fa[i]=i; int res=0; rep2(i,m,1){ int fx=findFa(edge[i].u); int fy=findFa(edge[i].v); if(fx!=fy){ fa[fx]=fy; res+=edge[i].c; } } int tx=findFa(1); rep(i,2,n) if(findFa(i)!=tx) return -1; return res;}bool isFibo[100005];void FiboD(){ mem(isFibo,false); int a=1,b=2; isFibo[1]=isFibo[2]=true; for(;;){ int t=a+b; a=b, b=t; if(t>100000) break; isFibo[t]=true; }}int main(){ //freopen("test.in","r",stdin); cin>>T; FiboD(); rep(t,1,T){ scanf("%d%d",&n,&m); rep(i,1,m) scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].c); sort(edge+1,edge+1+m,cmp); int mins=kruskal1(); int maxs=kruskal2(); printf("Case #%d: ",t); if(mins==-1 || maxs==-1) puts("No"); else{ bool flag=false; rep(i,mins,maxs) if(isFibo[i]){ flag=true; break; } if(flag) puts("Yes"); else puts("No"); } } //fclose(stdin);}
hdu 4786 Fibonacci Tree (最小、最大產生樹)