生活随笔
收集整理的這篇文章主要介紹了
树的重心
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
樹的重心
說明:下面的定義等都是按照個人的理解所表述的,如有錯誤歡迎批評指出。
1.定義:
去掉該節點,最大的連通塊(子樹)的節點數目最少,則該節點點稱作該樹的重心。
2.性質:
- 去掉一個重心后,生成的每個連通塊的節點數 <= 總節點數/2。
- 重心可能不止一個,一棵樹最多有兩個重心,且相鄰。
- 樹中所有點到重心的距離和最小。
- 兩棵樹通過一條邊相連,新樹的重心一定在原來兩棵樹重心的連線上(不同樹的兩個重心所構成的路徑)。
- 一棵樹添加或刪除一個節點,樹的重心最多移動一條邊的位置。
3.實例:
如下圖所示的一棵樹,可以很容易的看出,這棵樹的重心可以是2,也可以是3。去掉重心后,構成的最大連通塊節點數為3。比如,去掉2,得到的連通塊為:{1},{5},{3,4,6}。
4.題目和解題模板:
入門題目:POJ 1655,POJ 3107。
用樹形dp來求解重心
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std
;
const int N
= 5e4+5;
struct Edge
{int from
;int to
;int next
;
} edge
[N
<<1];
int head
[N
],id
;
int dp
[N
],siz
[N
];
int n
,minx
;
void init2()
{for(int i
= 1; i
<= n
; i
++){dp
[i
] = 0;siz
[i
] = 1;}minx
= 1 << 30;
}
void init()
{memset(head
,-1,sizeof(head
));id
= 0;
}
inline void add_edge(int from
,int to
)
{edge
[id
].from
= from
;edge
[id
].to
= to
;edge
[id
].next
= head
[from
];head
[from
] = id
++;
}void dfs(int u
,int fa
)
{for(int i
= head
[u
]; ~i
; i
= edge
[i
].next
){int to
= edge
[i
].to
;if(to
!= fa
){dfs(to
,u
);siz
[u
] += siz
[to
];dp
[u
] = max(dp
[u
],siz
[to
]);}}dp
[u
] = max(dp
[u
],n
-siz
[u
]);minx
= min(minx
,dp
[u
]);return;
}
int main()
{scanf("%d",&n
);init();for(int i
= 1; i
< n
; i
++){int x
,y
;scanf("%d%d",&x
,&y
);add_edge(x
,y
);add_edge(y
,x
);}init2();dfs(1,0);bool flag
= true
;for(int i
= 1; i
<= n
; i
++){if(dp
[i
] == minx
){if(flag
){printf("%d",i
);flag
= false
;continue;}printf(" %d",i
);}}puts("");return 0;
}
與50位技術專家面對面20年技術見證,附贈技術全景圖
總結
以上是生活随笔為你收集整理的树的重心的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。