Codeforces 538E. Demiurges Play Again (树形DP)

xiaoxiao2021-02-27  168

题目描述

传送门

题目大意:给出一个有根树,A,B两个人轮流操作。 给每个叶子节点分配权值[1..叶子节点数]的一个排列。每次每个人可以选择任意一条边走,A希望最后取得的叶子节点的权值尽可能大,B希望最后取得的叶子节点的权值尽可能的小,两个人都绝对聪明,问如果让A分配权值最后能得到的最大权值是多少,如果让B分配权值最后能得到的最小权值是多少。

题解

已A的操作为例。 f[i]表示到达节点i能获得其子树中第几大的权值。显然A可以控制奇数层的节点,B可以控制偶数层的节点。 轮到A操作的时候,他一定会选择 min(f[son]) ,安排权值的时候把所有最大的都放置到一棵子树上。 轮到B操作的时候,他会尽可能选择小的,所以A的目标就是使最小值最大,那么最好的方式就是平均分配。 最后B只能得到 f[son] B的操作也是一样的,不过用f[i]表示第几小即可。

代码

#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #define N 400003 using namespace std; int n,tot,nxt[N],v[N],point[N],f[N],deep[N],leaf; void add(int x,int y) { tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; } void dfs_A(int x,int fa) { deep[x]=deep[fa]+1; bool pd=false; if (deep[x]&1) { f[x]=n; for (int i=point[x];i;i=nxt[i]) { if (v[i]==fa) continue; dfs_A(v[i],x); f[x]=min(f[x],f[v[i]]); pd=true; } } else { for (int i=point[x];i;i=nxt[i]){ if (v[i]==fa) continue; dfs_A(v[i],x); f[x]=f[x]+f[v[i]]; pd=true; } } if (!pd) f[x]=1,leaf++; } void dfs_B(int x,int fa) { bool pd=false; if (!(deep[x]&1)){ f[x]=n; for (int i=point[x];i;i=nxt[i]) { if (v[i]==fa) continue; dfs_B(v[i],x); f[x]=min(f[x],f[v[i]]); pd=true; } } else { f[x]=0; for (int i=point[x];i;i=nxt[i]){ if (v[i]==fa) continue; dfs_B(v[i],x); f[x]=f[x]+f[v[i]]; pd=true; } } if (!pd) f[x]=1; } int main() { freopen("a.in","r",stdin); scanf("%d",&n); for (int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); add(x,y); } dfs_A(1,0); printf("%d ",leaf-f[1]+1); dfs_B(1,0); printf("%d\n",f[1]); }
转载请注明原文地址: https://www.6miu.com/read-12764.html

最新回复(0)