zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    Servlet设置Cookie无效
    IOS即时通讯XMPP搭建openfire服务器
    IOS之富文本编辑
    unittest单元测试框架总结
    杀死future处理的阻塞线程
    APP的UI设计原则
    如何降低一个程序的耦合性
    Hyperopt中文文档导读
    Hyperopt中文文档导读
    AdaBoost算法特性
  • 原文地址:https://www.cnblogs.com/morslin/p/11855697.html
Copyright © 2011-2022 走看看