题解 AT4995 【[AGC034E] Complete Compress】
推销博客:https://www.cnblogs.com/syc233/p/13603919.html
注意到数据范围很小,所以我们可以枚举一个根,尽量让所有点移动到这个点上。
将两颗距离至少为
- 它们的LCA为它们共同的祖先,则两颗棋子一同向LCA移动一步。
- 其中一颗棋子为LCA,则深度浅的棋子向下移动,深度深的棋子向上移动。
显然第二种情况对于寻找最优解是不利的,为了让所有点移动到根上,每个点都应向上跳。所以我们只考虑以第一种情况操作。
zzy:
这里就涉及到一个经典的模型:有若干个元素被分成了若干个集合, 每次要找两个在不同集合中的元素匹配然后消掉。
设所有集合的总大小为
再回到这道题。
考虑树上的一个点
但是由于树结构的限制,有祖孙关系的两个点对应的集合不能同时选择。因此我们考虑树形DP,将问题转化为互不相交的子问题求解。
令
以
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define maxn 2005
#define Rint register int
#define INF 0x3f3f3f3f
using namespace std;
typedef long long lxl;
template <typename T>
inline void read(T &x)
{
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
x*=f;
}
struct edge
{
int u,v,next;
}e[maxn<<1];
int head[maxn],k;
inline void add(int u,int v)
{
e[k]=(edge){u,v,head[u]};
head[u]=k++;
}
int n,a[maxn];
int siz[maxn],dis[maxn],f[maxn];
inline void dfs(int u,int fa)
{
siz[u]=a[u];
dis[u]=0;
int son=-1;
for(int i=head[u];~i;i=e[i].next)
{
int v=e[i].v;
if(v==fa) continue;
dfs(v,u);
siz[u]+=siz[v];
dis[u]+=(dis[v]+=siz[v]);
if(!~son||dis[son]<dis[v]) son=v;
}
if(!~son) return void(f[u]=0);
if(dis[u]-dis[son]>=dis[son]) f[u]=dis[u]/2;
else f[u]=dis[u]-dis[son]+min(f[son]*2,2*dis[son]-dis[u])/2;
}
char s[maxn];
int main()
{
// freopen("AT4995.in","r",stdin);
read(n);
scanf(" %s",s+1);
for(int i=1;i<=n;++i) a[i]=s[i]-'0';
memset(head,-1,sizeof(head));
for(int i=1,u,v;i<n;++i)
{
read(u),read(v);
add(u,v);add(v,u);
}
int ans=-1;
for(int i=1;i<=n;++i)
{
dfs(i,0);
if(f[i]*2==dis[i]) ans=(!~ans||ans>f[i])?f[i]:ans;
}
printf("%d\n",ans);
return 0;
}