POI2011 DYN-Dynamite

Posted morslin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POI2011 DYN-Dynamite相关的知识,希望对你有一定的参考价值。

题目传送门

DP是不可能DP的,只会搜索


先二分距离,然后此题转化为最小点覆盖,即选择最少的点去覆盖关键节点,覆盖范围为二分的(mid)
对于覆盖,大部分题解都是用的DP,但是用剪枝后的搜索也能水过去

对于每个关键节点,如果它已经被覆盖了,就不管它,否则选择它的(k)级祖先进行覆盖
在用DFS进行覆盖的时候,可能会有一个点(x)被覆盖多次,但只有离(x)最近的一个覆盖点才是最有用的
所以可以用一个vis[x]表示覆盖点覆盖到到(x),还剩下多少距离可以继续覆盖,只有当前DFS剩下的距离大于vis[x]时才继续搜索(x)

虽然这种优化可以AC,但应该还是可以被卡掉的,毕竟时间复杂度最坏是(O(n^2))。写这篇题解的目的只是提醒一下,搜索+剪枝往往会有奇效

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
using namespace std;
LL read() {
    LL k = 0, f = 1; char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9')
        k = k * 10 + c - 48, c = getchar();
    return k * f;
}
struct zzz {
    int t, nex;
}e[300010 << 1]; int head[300010], tot;
void add(int x, int y) {
    e[++tot].t = y;
    e[tot].nex = head[x];
    head[x] = tot;
}
bool val[300010]; int f[300010];
int q[300010], h = 1, t = 0;
int vis[300010];
void bfs(int s) { //预处理
    q[++t] = s; vis[s] = 1;
    while(h <= t) {
        int x = q[h]; ++h;
        for(int i = head[x]; i; i = e[i].nex) {
            if(vis[e[i].t]) continue;
            q[++t] = e[i].t; f[e[i].t] = x;
            vis[e[i].t] = 1;
        }
    }
}
void dfs(int pos, int fa, int k) { //覆盖
    vis[pos] = k; if(!k) return ;
    for(int i = head[pos]; i; i = e[i].nex) {
        if(vis[e[i].t] < k-1) dfs(e[i].t, pos, k-1);
    }
}
void update(int pos, int k) { //找k级祖先
    int x = pos;
    for(int i = 1; i <= k && f[x]; ++i) x = f[x];
    dfs(x, x, k);
}
int n, m;
bool judge(int k) {
    memset(vis, -1, sizeof(vis));
    int tot = 0;
    for(int i = n; i >= 1; --i) {
        if(vis[q[i]] == -1 && val[q[i]]) {
            update(q[i], k), ++tot;
            if(tot > m) return 0;
        }
    }
    return 1;
}
int main() {
    n = read(), m = read();
    for(int i = 1; i <= n; ++i) val[i] = read();
    for(int i = 1; i <= n-1; ++i) {
        int x = read(), y = read();
        add(x, y); add(y, x);
    }
    bfs(1);
    int l = 0, r = n;
    while(l < r) {
        int mid = (l + r) >> 1;
        if(judge(mid)) r = mid;
        else l = mid+1;
    }
    cout << l;
    return 0;
}

以上是关于POI2011 DYN-Dynamite的主要内容,如果未能解决你的问题,请参考以下文章

树形动规专题

POI2011 棒棒糖 Lollipop

BZOJ2212 [Poi2011]Tree Rotations 线段树合并 逆序对

bzoj 2212 : [Poi2011]Tree Rotations (线段树合并)

java poi xwpf操作word生成一个表格怎么合并单元格,求大神指导!

雷林鹏分享:Apache POI电子表格/Spreadsheet