1. 程式人生 > >Achen毒瘤模擬賽T2——毒瘤最優化

Achen毒瘤模擬賽T2——毒瘤最優化

fine ret turn 優化 樹的重心 ace set etc node

題目大意:給出一棵樹,樹的生成圖G上任意兩點相連且兩點的距離為樹上兩點的帶權距離,求圖上最短的哈密頓回路。

坑點:如果一直想從哈密頓回路入手,那你就要GG了,像我一樣想出一個錯解DP。

然而,只需畫幾個圖,你就會大致猜出一個方法:以樹的重心為根,把書分為若幹部分且每個部分大小不超過n/2,那麽必定有一種方法使得lca全部取得根,所以對於一條邊(u,pre[u]),他會被經過2*s[u]次。

然後就可以依次計算最小值了(?????為什麽?????)

這裏有一個引理:有n個不同顏色的小球,若出現次數最多的顏色的小球能被分隔開,則一定存在一種排列方式使任意相鄰小球不同色。證明很簡單,由於出現次數最多的小球能被隔開,按BFS方式每次取出一種顏色的球,這樣一定會剩下出現次數最多的球,再把這些球插進序列中就好。由於保證了出現次數最多的顏色的小球能被分隔開,所以這個操作一定能成功

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<queue>
#include<ctime>
#define MAXN 200005
#define ll long long
#define maxn 15
#define maxs 1000005
#define inf 1e9
#define eps 1e-9
using namespace
std; inline char gc() { static char now[1<<16],*S,*T; if (T==S) { T=(S=now)+fread(now,1,1<<16,stdin); if (T==S) return EOF; } return *S++; } inline ll readlong() { ll x=0,f=1; char ch=getchar(); while(ch<0||ch>9) { if(ch==-)f=-1
; ch=getchar(); } while(ch>=0&&ch<=9) { x*=10; x+=ch-0; ch=getchar(); } return x*f; } inline int read() { int x=0,f=1; char ch=getchar(); while(ch<0||ch>9) { if(ch==-)f=-1; ch=getchar(); } while(ch>=0&&ch<=9) { x*=10; x+=ch-0; ch=getchar(); } return x*f; } void putint(long long t) { int ans[40]= {0}; for(; t; t/=10)ans[++ans[0]]=t%10; for(; ans[0]; ans[0]--)putchar(0+ans[ans[0]]); putchar(\n); } const int N=1000005; struct node{ int to,nxt; }e[N<<1]; int h[N],cnt; void add(int x,int y){ e[++cnt]=(node){y,h[x]}; h[x]=cnt; e[++cnt]=(node){x,h[y]}; h[y]=cnt; } int sum[N],ans[N]; int tot; int n; void dfs(int x,int fa){ sum[x]=1; for(int i=h[x];i;i=e[i].nxt){ int y=e[i].to; if(y==fa){ continue; } dfs(y,x); sum[x]+=sum[y]; } if(fa){ ans[++tot]=2*min(sum[x],n-sum[x]); } } int main(){ n=read(); for(int i=1;i<n;i++){ int x=read(); int y=read(); add(x,y); } dfs(1,0); sort(ans+1,ans+tot+1); ll A=0; for(int i=1;i<=tot;i++){ A=(A+1ll*i*ans[tot-i+1]); } printf("%lld\n",A); return 0; }

Achen毒瘤模擬賽T2——毒瘤最優化