AT4995-[AGC034E] Complete Compress【树形dp】
正題
題目鏈接:https://www.luogu.com.cn/problem/AT4995
題目大意
nnn個點的一棵樹,上面有一些棋子,每次可以選擇兩個棋子移動到他們之間的路徑上相鄰的點上,求最少多少步能移動到一個點上。
n∈[1,2000]n\in[1,2000]n∈[1,2000]
解題思路
如果固定最終節點的話,這個節點rtrtrt可行的話那么答案一定是∑dis(rt,x)2\frac{\sum dis(rt,x)}{2}2∑dis(rt,x)?。
那么現在就轉變為一個判定性問題,我們現在的操作變為了每次選擇兩個沒有祖先關系的點,然后將它們往它們的LCALCALCA處移動一格。
同樣的,我們發現如果我們在處理一個點xxx作為LCALCALCA時,我只會關心所有節點來自它的哪個兒子而不用考慮具體的位置。所以可以搞樹形dpdpdp。
設fxf_xfx?表示xxx的子樹內最多的移動次數,定義sx=∑y∈subtree(x)dis(x,y)s_x=\sum_{y\in subtree(x)}dis(x,y)sx?=∑y∈subtree(x)?dis(x,y)的話,那么我們的轉移和max{sy}(x?>y)max\{s_y\}(x->y)max{sy?}(x?>y)有關。
若max{sy}×2≤sxmax\{s_y\}\times 2\leq s_xmax{sy?}×2≤sx?,那么這里面的節點可以兩兩配對,fx=sx2f_x=\frac{s_x}{2}fx?=2sx??。
否則他sss最大的子樹yyy之中會有剩余的節點無法相互匹配,那么有fx=sx?sy+min{fy,sy??sx2?}f_x=s_x-s_y+min\{f_y,s_y-\lfloor\frac{s_x}{2}\rfloor\}fx?=sx??sy?+min{fy?,sy???2sx???}
然后如果fx=sx2f_x=\frac{s_x}{2}fx?=2sx??那么xxx就是可行的答案
時間復雜度O(n2)O(n^2)O(n2)
code
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=2100; struct node{int to,next; }a[N<<1]; int n,tot,ls[N],s[N],w[N],f[N],ans; char v[N]; void addl(int x,int y){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;return; } void dp(int x,int fa){s[x]=w[x]=0;int mx=0,son=0;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(y==fa)continue;dp(y,x);w[x]+=w[y];s[x]+=s[y]+w[y];if(s[y]+w[y]>mx)mx=s[y]+w[y],son=y;}if(mx*2>s[x])f[x]=s[x]-mx+min(f[son],mx-s[x]/2);else f[x]=s[x]/2;w[x]+=(v[x]=='1');return; } int main() {scanf("%d",&n);scanf("%s",v+1);for(int i=1;i<n;i++){int x,y;scanf("%d%d",&x,&y);addl(x,y);addl(y,x);}ans=1e9;for(int i=1;i<=n;i++){dp(i,i);if(s[i]&1)continue;if(f[i]==s[i]/2)ans=min(ans,f[i]);}if(ans==1e9)puts("-1");else printf("%d\n",ans);return 0; } 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的AT4995-[AGC034E] Complete Compress【树形dp】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑都识别了硬盘电脑都识别了硬盘怎么办
- 下一篇: 不打游戏的电脑该用什么配置不打游戏的电脑