1 条题解
-
3
覆盖(cover)
你有 个点的树,初始每一条边都没有颜色。
你有两种覆盖操作:
- 选择 满足 路径上的边都没有颜色,然后将他们路径 上的边都染色。
- 选择 满足 的邻边都没有被染色,然后将 的邻边染色。
要求用最少次数将所有边染色。
。
首先你应该模拟大样例。
然后观察以 为根的最优解结构:必然为如下两种状态:
- 在这个点执行了邻边覆盖,那么这个点就会覆盖其父边。然后其就需要累加每一个儿子的答案,因为一个邻边覆盖会切断 与儿子的联系。但是儿子的父边不能被覆盖。所以,我们至少应该设出关于 的两个状态: 表示 有/没有覆盖父边。那么只需要 。
- 这个点不执行任何东西。那么他需要将儿子和连接儿子的边进行连接,然后转移。然后你就会发现这样一个结构:如果说 有 个儿子没有覆盖其父边,那么最优解肯定是让这 个儿子两两配对。因此,这就涉及到奇偶性。
所以我们要这样设计: 表示 为根的子树:
- :有偶数个没有覆盖父边的儿子;
- :有奇数个没有覆盖父边的儿子;
- :自己覆盖了父边。
那么根据上面的分析,我们可以列出转移:
然后对于奇数和偶数,是差不多的。不妨只看奇数。
首先对于新的儿子 ,如果他覆盖了父边,那么 和 被切断了,完全独立。于是有:
然后,如果 没有覆盖父边,那么有两种情况:
- :这种情况下, 有一个额外伸出来没有匹配的树链,那么这个树链可以和 到 的边进行连接,一起覆盖,那么就有:;
- :这种情况下, 没有额外的树链,那么这个时候 到 的边单独成为一个树链。于是:。
然后就没了, 的转移是类似的,只要减去 即可(因为可以和别的匹配)。
#include <bits/stdc++.h> #define int long long using namespace std; const int N=100010,inf=1e9; int n,f[N][3]; vector<int>v[N]; void dfs(int x,int fa){ f[x][0]=f[x][1]=f[x][2]=inf; f[x][0]=0;f[x][2]=1; for(int u:v[x]){ if(u==fa)continue; dfs(u,x); f[x][2]+=min(f[u][0],f[u][1]); int t0=f[x][0],t1=f[x][1]; f[x][1]=min({t1+f[u][2],t0+f[u][1],t0+f[u][0]+1}); f[x][0]=min({t0+f[u][2],t1+f[u][1]-1,t1+f[u][0]}); } } signed main(){ scanf("%lld",&n); for(int i=1,x,y;i<n;i++){ scanf("%lld%lld",&x,&y); v[x].push_back(y); v[y].push_back(x); } dfs(1,0); printf("%lld",min({f[1][0],f[1][1],f[1][2]})); return 0; }
- 1
信息
- ID
- 2813
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 7
- 标签
- (无)
- 递交数
- 12
- 已通过
- 2
- 上传者