• LuoguP1041 传染病控制


    题目地址

    题目链接

    题解

    这里讲一个非正解——贪心+随机化
    贪心的想法是什么?
    我们dfs一遍处理出每个节点子树内的节点数量,记为(siz)
    贪心的砍掉(siz)最大的那个子树,在树的形态比较正常的情况下是可以得到最优解的。
    如何hack掉这种贪心?
    构造一条链,在中间的地方放一个“很胖”的分支,可以只分两层,每层的节点构造多一些(注意要使这个分支的节点数量小于链下半部分的节点数量)
    这样子我们按照上述贪心,将会得到错误的结果,更优的做法是把这个分支直接砍掉(因为链上每次传染只会增加一个被传染的人)
    当然,实际构造可以更加复杂,这只是最极端的情况。
    不过,这种错误的贪心已经可以得到90分了。
    如何得到满分?
    要对答案产生影响,那么需要的那个分支的大小就不会太小(因为实际情况下一般是不会像上面那样子构造的,毒瘤出题人除外
    我们采用随机化的思想(实际上下面这个随机化的方法并不好,不过数据水也就水过去了)。
    我们定义一种判定规则,如果某个节点恰好符合这个判定规则(一般是随机的),那么就改变原本的贪心策略,换用另外一个策略。
    这里用的判定规则是rand出来的结果对233取模是否为0.
    如果符合这个判定规则的话,我们就选择子树大小第二大(这个使用优先队列实现)的子树砍掉。
    当然,这很不靠谱。
    通常的做法是在不TLE的情况下尽量跑多次(能多少次就多少次),对所有结果取min。
    所以随机化能水过去一般靠大量的尝试,尽量靠谱的判定规则,以及另外一个策略靠不靠谱。。。
    注意,在此题中,需要使判定成功的可能性尽可能低,当然也不能太低
    下面给出代码,注意,因为代码里只跑了200次进行尝试,不保证一定能ac,可以自行调大次数,或者多交几次(我交了2发才过)。

    #include <bits/stdc++.h>
    
    #define ll long long
    #define inf 0x3f3f3f3f
    #define il inline
    
    namespace io {
    
        #define in(a) a=read()
        #define out(a) write(a)
        #define outn(a) out(a),putchar('
    ')
    
        #define I_int ll
        inline I_int read() {
            I_int x = 0 , f = 1 ; char c = getchar() ;
            while( c < '0' || c > '9' ) { if( c == '-' ) f = -1 ; c = getchar() ; }
            while( c >= '0' && c <= '9' ) { x = x * 10 + c - '0' ; c = getchar() ; }
            return x * f ;
        }
        char F[ 200 ] ;
        inline void write( I_int x ) {
            if( x == 0 ) { putchar( '0' ) ; return ; }
            I_int tmp = x > 0 ? x : -x ;
            if( x < 0 ) putchar( '-' ) ;
            int cnt = 0 ;
            while( tmp > 0 ) {
                F[ cnt ++ ] = tmp % 10 + '0' ;
                tmp /= 10 ;
            }
            while( cnt > 0 ) putchar( F[ -- cnt ] ) ;
        }
        #undef I_int
    
    }
    using namespace io ;
    
    using namespace std ;
    
    #define N 310
    
    int n, m, f[N];
    int cnt, head[N], siz[N], fa[N];
    struct edge {
    	int to, nxt;
    }e[N<<1];
    
    void ins(int u, int v) {
    	e[++cnt] = (edge) {v, head[u]};
    	head[u] = cnt;
    }
    
    void dfs(int u) {
    	siz[u] = 1;
    	for(int i = head[u]; i; i = e[i].nxt) {
    		if(e[i].to == fa[u]) continue;
    		fa[e[i].to] = u;
    		dfs(e[i].to);
    		siz[u] += siz[e[i].to];
    	}
    }
    
    struct Node {
        int val;
    };
    priority_queue<Node> q, t;
    
    bool operator < (Node a, Node b) {
        return siz[a.val] < siz[b.val];
    }
    
    int solve() {
        while(!q.empty()) q.pop();
        int ans = 0;
        q.push((Node){1});
        while(!q.empty()) {
            int cur = 0;
            while(!t.empty()) t.pop();
            while(!q.empty()) {
                int u = q.top().val; ++ans;
                for(int i = head[u]; i; i = e[i].nxt) {
                    if(e[i].to == fa[u]) continue;
                    t.push((Node){e[i].to});
                    f[++cur] = e[i].to;
                }
                q.pop();
            }
            int num;
            if(!t.empty()) {
                int u = t.top().val; t.pop();
                if(!t.empty() && rand() % 233 == 0) {
                    num = t.top().val; t.pop();
                } else num = u;
            }
            for(int i = 1; i <= cur; ++i) {
                if(f[i] == num) continue;
                q.push((Node){f[i]});
            }
        }
        return ans;
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("1.in", "r", stdin);
    #endif
        srand((unsigned)time(0));
    	n = read(), m = read();
    	for(int i = 1; i <= m; ++i) {
    		int u = read(), v = read();
    		ins(u, v); ins(v, u);
    	}
    	dfs(1);
        int ans = 1000000;
    	for(int i = 1; i <= 200; ++i) {
            ans = min(ans, solve());
        }
        printf("%d
    ", ans);
    }
    

    过段时间补个搜索做法

  • 相关阅读:
    python 二分法查找
    python 线性查找
    Ubuntu14.04 获取文件或者文件夹大小
    Python异常处理
    python 正则
    Python网络编程(Sockets)
    Python多线程编程
    Python XML解析和处理
    python 迭代器
    python 装饰器
  • 原文地址:https://www.cnblogs.com/henry-1202/p/10371500.html
Copyright © 2020-2023  润新知