POJ 1655 +POJ 3107【求樹的重心】
阿新 • • 發佈:2019-02-05
樹的重心:樹的重心也叫樹的質心。找到一個點,其所有的子樹中最大的子樹節點數最少,那麼這個點就是這棵樹的重心,刪去重心後,生成的多棵樹儘可能平衡。
兩個都是模板題,主要還是對樹的重心的理解。簡單的DFS的應用,記錄每次刪除當前結點之後每個子樹的最大節點數,最小化最大節點數就是樹的重心,在一棵樹中,樹的重心可能不止一個。
換句話說,刪除這個點後最大連通塊(一定是樹)的結點數最小。
eg:
刪除1:子樹1:2、6 子樹2:4、5 子樹3:3、7 ans[1]=2;
刪除2:子樹1:6 子樹2:1、3、4、5、7 ans[2]=5;
刪除3:子樹1:7 子樹2:1、2、4、5、6 ans[3]=5;
刪除4:子樹1:5 子樹2:1、2、3、6、7 ans[4]=5;
刪除5:子樹1:1、2、3、4、6、7 ans[5]=6;
刪除6:子樹1:1、2、3、4、5、7 ans[6]=6;
刪除7:子樹1:1、2、3、4、5、6 ans[7]=6;
因此,樹的重心為cnt=min(ans[i],cnt)=2;
題目大意:給定一棵樹,求樹的重心的編號以及重心刪除後得到的最大子樹的節點個數size,如果有多個重心即size相同就選取編號最小的。
CODE:
const int maxn=500005; int tot=0,n; int ans,size; int sx[maxn],head[maxn]; int vis[maxn]; struct edge { int to,next; } eg[maxn]; void add(int u,int v) { eg[tot].to=v; eg[tot].next=head[u]; head[u]=tot++; } void init() { tot=0; memset(head,-1,sizeof(head)); memset(vis,0,sizeof(vis)); } void dfs(int u) { vis[u]=1; sx[u]=1; int tmp=0; for(int i=head[u]; i!=-1; i=eg[i].next) { int v=eg[i].to; if(!vis[v]) { dfs(v); sx[u]+=sx[v]; tmp=max(tmp,sx[v]); } } tmp=max(tmp,n-sx[u]); if(size>tmp||size==tmp&&ans>u) { ans=u; size=tmp; } } int main() { int t; scanf("%d",&t); while(t--) { init(); int u,v; scanf("%d",&n); for(int i=1; i<n; i++) { scanf("%d%d",&u,&v); add(u,v); add(v,u); } size=INF; dfs(1); printf("%d %d\n",ans,size); } }
題目大意:給定一棵樹,求樹的所有重心,按照編號從小到大的順序輸出。
CODE:
const int maxn=100005; struct node { int to,next; } eg[maxn]; int tot=0,num=0,n; int vis[maxn],sx[maxn],ans[maxn]; int head[maxn]; void add(int u,int v) { eg[tot].to=v; eg[tot].next=head[u]; head[u]=tot++; } int size,cnt; void dfs(int u) { vis[u]=1; sx[u]=1; int tmp=0; for(int i=head[u]; i!=-1; i=eg[i].next) { int v=eg[i].to; if(!vis[v]) { dfs(v); sx[u]+=sx[v]; tmp=max(tmp,sx[v]); } } tmp=max(tmp,n-sx[u]); if(tmp<size) { //printf("&&&&&&\n"); num=0; size=tmp; ans[num++]=u; } else if(tmp==size) { //printf("*********\n"); ans[num++]=u; } } void init() { tot=0,num=0; memset(vis,0,sizeof(vis)); memset(head,-1,sizeof(head)); memset(ans,0,sizeof(ans)); size=INF; } int main() { while(~scanf("%d",&n)) { init(); int u,v; for(int i=1; i<n; i++) { scanf("%d%d",&u,&v); add(u,v); add(v,u); } dfs(1); sort(ans,ans+num); for(int i=0; i<num; i++) { if(i) printf(" "); printf("%d",ans[i]); } printf("\n"); } return 0; }
兩個都是模板題,主要還是對樹的重心的理解。簡單的DFS的應用,記錄每次刪除當前結點之後每個子樹的最大節點數,最小化最大節點數就是樹的重心,在一棵樹中,樹的重心可能不止一個。