洛谷P3441 [POI2006]MET-Subway
? 解题记录 ? ? 洛谷 ? ? 贪心 ?    2018-09-18 09:44:16    356    0    0

题目描述

给定一棵树,选择l条路径覆盖最多的点的个数是多少。 

输入输出样例

输入样例#1: 复制
17 3
1 2
3 2
2 4
5 2
5 6
5 8
7 8
9 8
5 10
10 13
13 14
10 12
12 11
15 17
15 16
15 10
输出样例#1: 复制
13​​

 

 很好的一道题,果然我的贪心技巧还不够。

观察因为可以重叠,我们选叶子作为端点一定是最优的,因为如果不到叶子结点那么向叶子结点延伸一定可以覆盖更多点,因此在叶子很多的情况下我们选2*l个叶子。

接下来一步就比较巧妙了,我们换一个角度,从结果来思考。最后覆盖出的路径一定是从叶子向内延伸的,那么就算有再多的叶子只要上一层的节点数m<2*l那么也只能覆盖m个节点,并且之后也只能向上延伸m。因此我们对树拓扑排序算出每层的节点数模拟就行了。

#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 1e6 + 5;
int n, l;
struct edge {
    int v, next;
} e[maxn << 1];

int head[maxn], cnt, ans, fa[maxn];
int depth[maxn], tot[maxn];
void adde(const int &u, const int &v) {
    e[++cnt] = (edge) {v, head[u]};
    head[u] = cnt;
}

int u, v, deg[maxn], vis[maxn], pos = -1;
queue<int > q;

int main() {
    scanf("%d%d", &n, &l);
    for(register int i = 1; i <= n - 1; ++i) {
        scanf("%d%d", &u, &v);
        adde(u, v), adde(v, u);
        ++deg[u], ++deg[v];
    }
    for(register int i = 1; i <= n; ++i)
        if(deg[i] == 1) q.push(i), ++tot[0], vis[i] = 1;
    while(!q.empty()) {
        int u = q.front(), v;
        q.pop();
        for(register int i = head[u]; i; i = e[i].next) {
            v = e[i].v;
            if(--deg[v] == 1) {
                q.push(v), vis[v] = 1;
                depth[v] = depth[u] + 1;
                ++tot[depth[v]];
            }
        }
    }
    for(register int i = 0; i <= n; ++i)
        ans += min(tot[i], 2 * l);
    printf("%d", ans);
    return 0;
}


上一篇: CF#509 Div2 F. Ray in the tube

下一篇: CF#509 Div2 E. Tree Reconstruction

356 人读过
立即登录, 发表评论.
没有帐号? 立即注册
0 条评论
文档导航