51Nod 1322 - 關於樹的函式(樹DP)
阿新 • • 發佈:2019-01-13
【題目描述】
【思路】
看了大佬的題解才想明白的,f_zyj大佬的題解
兩棵樹,對第一棵樹暴力列舉所有邊,拆掉這條邊後的兩個子樹對應兩個集合
,用
列舉,然後在枚舉出某一個
時,所有在
中的節點
,
,現在對第二棵樹列舉,
列舉的時候和剛才
不同,這回是把節點
和
的所有子孫看成集合
,樹上的其它節點看成是集合
,這樣一來,可以遞推的計算集合中元素的個數已經
交集的大小,設第二棵樹上節點
對應的集合大小為
,和
的交集大小為
,如果
的所有兒子節點所在集合為
,那麼就有
而且只要知道
的交集大小,並且
交集為空,
交集為空,因此其餘三對集合的交集大小也能推算出來,取一下最大值,不過題解裡的“樹歸”是個啥?樹上遞迴嗎?不是很懂…
#include<bits/stdc++.h>
#define max(a,b)(a>b?a:b)
using namespace std;
const int maxn=4005;
struct Edge{
int from,to;
Edge(int f=0,int t=0):from(f),to(t){}
};
int n,a1;
long long ans;
bool used[maxn];
int num[maxn],dp[maxn];
vector<int> g1[maxn],g2[maxn];
Edge edges[maxn];
void dfs1(int u,int fa){
used[u]=true;
++a1;
for(int i=0;i<g1[u].size();++i){
int v=g1[u][i];
if(v!=fa && !used[v]) dfs1(v,u);
}
}
void dfs2(int u,int fa){
num[u]=1;
dp[u]=used[u]?1:0;
for(int i=0;i<g2[u].size();++i){
int v=g2[u][i];
if(v!=fa){
dfs2(v,u);
num[u]+=num[v];
dp[u]+=dp[v];
}
}
if(u!=0){//u=0時樹沒有被分成兩部分所以不算
int b1=num[u];
//集合a1和b1的交集大小為dp[u]
int maxv=0;
maxv=max(maxv,dp[u]);
maxv=max(maxv,a1-dp[u]);
maxv=max(maxv,b1-dp[u]);
maxv=max(maxv,n-a1-b1+dp[u]);
ans+=(long long)maxv*maxv;
}
}
int main(){
scanf("%d",&n);
for(int i=0;i<n-1;++i){
int u,v;
scanf("%d%d",&u,&v);
g1[u].push_back(v);
g1[v].push_back(u);
edges[i]=Edge(u,v);
}
for(int i=0;i<n-1;++i){
int u,v;
scanf("%d%d",&u,&v);
g2[u].push_back(v);
g2[v].push_back(u);
}
for(int i=0;i<n-1;++i){
a1=0;
memset(used,0,sizeof(used));
dfs1(edges[i].from,edges[i].to);
dfs2(0,-1);
}
printf("%lld\n",ans);
return 0;
}