1. 程式人生 > >UVALive - 6436 —(DFS+思維)

UVALive - 6436 —(DFS+思維)

long long 我們 space cli 最大 %d while 復雜 路徑

技術分享圖片

技術分享圖片

技術分享圖片

題意:n個點連成的生成樹(n個點,n-1條邊,點與點之間都連通),如果某個點在兩點之間的路徑上,那這個點的繁榮度就+1,問你在所有點中,最大繁榮度是多少?就比如上面的圖中的C點,在A-B,A-D,A-E,A-F,B-D,B-E,B-F的路徑上,所以繁榮度為7。

思路:我們可以想一下,繁榮度是怎麽來的?假設一個點的度是2,相當於以這個點為根,有兩棵子樹,那繁榮度就是這兩棵子樹上各取一個點兩兩組合,最後的結果就是兩棵子樹上的點的乘積。所以不難推出,若度大於2,那繁榮度就是所有子樹上的點樹兩兩相乘的和,例如上圖的C點,度為3,且3個度包含的點的個數分別為1,1,3,繁榮度 = 1*1 + 1*3 + 1*3 = 7。


然而,這樣的計算方式復雜度有點高,若度為n,光計算繁榮度就要O(n*n),更何況這只是一個點的繁榮度。所以,我們還可以簡化一下計算方式:

計算出每一棵子樹的點的個數,用每個子樹的點的個數乘以除了這棵子樹以及根節點以外剩余的點,,每棵子樹都這樣計算,並將結果相加,求出的和除以2,就是結果。

因為這樣的計算方式和之前相比,相當於兩兩之間都乘了兩次,子樹1*所有子樹的和(除自己) = 子樹1*子樹2* + 子樹1*子樹3 + ..... + 子樹1*子樹n, 子樹2*所有子樹的和(除自己) = 子樹2*子樹1 + 子樹2*子樹3 + ... + 子樹2*子樹n;這之中,子樹1*子樹2 ,又子樹2*1子樹,計算了兩次,所以最終結果要除以2。

我們可以將整個圖看成一顆以節點1為根的樹,這樣將會簡化很多。除此之外,還可以使用鏈式前向星,記錄下某個點於那些點直接相連。

具體看代碼:

 1 #include<iostream> 
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<string>
 5 #include<cmath>
 6 #include<algorithm>
 7 #include<stack>
 8 #include<climits>
 9
#include<queue> 10 #define eps 1e-7 11 #define ll long long 12 #define inf 0x3f3f3f3f 13 #define pi 3.141592653589793238462643383279 14 using namespace std; 15 const int maxn = 20007; 16 int head[maxn],num,n; 17 ll ans,sum,size[maxn]; 18 struct node{ 19 int to,next; 20 }edge[maxn<<1]; 21 22 void add(int u,int v) //使用鏈式前向星計算每個點於那些點直接相連 23 { 24 edge[num].to = v; 25 edge[num].next = head[u]; 26 head[u] = num++; 27 } 28 29 void DFS(int u,int fa) //將整個圖看成一棵樹,u為當前節點,fa為父親節點 30 { 31 ll res = 0; 32 size[u] = 1; //size[u]表示以u為根的樹有多少個節點 33 for(int i=head[u]; i!=-1; i=edge[i].next) //遍歷所有子樹 34 { 35 int to = edge[i].to; 36 if(to == fa) continue; //不計算父親節點 37 DFS(to,u); 38 size[u] += size[to]; //以u為根的樹的節點總數等於他所有子樹的節點樹之和 39 res += (n - size[to] - 1)*size[to]; //計算子樹與其他剩余點的乘積 40 } 41 res += ( n - size[u] )*(size[u]-1); //除所有子樹外,u的根節點連成的樹也是以u為根的一課子樹 42 ans = max(ans,res/2); 43 return; 44 } 45 46 int main() 47 { 48 int t,cnt = 1; 49 cin>>t; 50 while(t--) 51 { 52 ans = -1; 53 num = 0; 54 memset(head,-1,sizeof(head)); 55 memset(size,0,sizeof(size)); 56 scanf("%d",&n); 57 int start,end; 58 for(int i=0; i<n-1; ++i) 59 { 60 scanf("%d%d",&start,&end); 61 add(start,end); //start於end直接相連 62 add(end,start);//無向圖,反過來也相連 63 } 64 DFS(1,-1); 65 printf("Case #%d: %lld\n",cnt++,ans); 66 } 67 return 0; 68 }

UVALive - 6436 —(DFS+思維)