zoukankan      html  css  js  c++  java
  • BZOJ3037创世纪

    解析

    首先如果考虑是树的情况那建完反图就跑一个dp就完事了。设 (dp[x][0/1]) 代表节点 (x) 选还是不选。有转移方程:(dp[x][0]=sum_{yin son(x)} max(dp[y][0],dp[y][1]))(dp[x][1]=dp[x][0]-(min_{yin son(x)} max(dp[y][0],dp[y][1]))+1)

    但这是一道基环树,其实差不多。首先基环树的套路就是先找到还然后再在环上处理。考虑是强行断环还是复制一遍。

    这道题应该是强行断环,假设断的是 ((s,t)) 这一条边(这里是原图),那么分两种情况讨论。

    1. s一定不选。这种情况碰到t的时候(dp[t][1])就直接等于(dp[t][0]+1)就好了。最后答案是(dp[s][0])

    2. s一定选。这种情况就直接正常跑就好了。最后答案是(dp[s][1])

    代码

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN = 1000005;
    template <typename T> void read(T &x) {
    	T f = 1;
    	char ch = getchar();
    	for (; '0' > ch || ch > '9'; ch = getchar()) if (ch == '-') f = -1;
    	for (x = 0; '0' <= ch && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
    	x *= f;
    }
    int n;
    int fa[MAXN];
    int u, v;
    vector<int> vec[MAXN];
    bool vis[MAXN];
    int dp[MAXN][2];
    int ans;
    void get_loop(int x) {
    	if (vis[x]) {
    		u = x;
    		v = fa[x];
    		return;
    	}
    	vis[x] = true;
    	get_loop(fa[x]);
    }
    void dfs(int x, bool zsy) {
    	dp[x][0] = dp[x][1] = 0;
    	vis[x] = 1;
    	for (int i = 0; i < (int)vec[x].size(); i++) {
    		int y = vec[x][i];
    		if (y != u) {
    			dfs(y, zsy);
    			dp[x][0] += max(dp[y][0], dp[y][1]); 
    		}
    	}
    	if (zsy) {
    		if (x == v) {
    			dp[x][1] = dp[x][0] + 1; 
    		} else {
    			for (int i = 0; i < (int)vec[x].size(); i++) {
    				int y = vec[x][i];
    				if (y != u) {
    					dp[x][1] = max(dp[x][1], dp[x][0] - max(dp[y][0], dp[y][1]) + dp[y][0] + 1);
    				}
    			}
    		}
    	} else {
    		for (int i = 0; i < (int)vec[x].size(); i++) {
    			int y = vec[x][i];
    			if (y != u) {
    				dp[x][1] = max(dp[x][1], dp[x][0] - max(dp[y][0], dp[y][1]) + dp[y][0] + 1);
    			}
    		}
    	}
    }
    int main() {
    	read(n);
    	for (int i = 1; i <= n; i++) {
    		read(fa[i]);
    		vec[fa[i]].push_back(i);
    	}
    	for (int i = 1; i <= n; i++) {
    		if (!vis[i]) {
    			int cur = 0;
    			get_loop(i);
    			dfs(u, 1);
    			cur = max(cur, dp[u][0]);
    			dfs(u, 0);
    			cur = max(cur, dp[u][1]);
    			ans += cur;
    		}
    	}
    	printf("%d", ans);
    	return 0;
    }
    

    编辑

  • 相关阅读:
    fiber
    ACM用到的算法。先做个笔记,记一下
    matlab安装及破解
    银行家算法
    网络安全(超级详细)零基础带你一步一步走进缓冲区溢出漏洞和shellcode编写!
    心脏滴血漏洞复现(CVE-2014-0160)
    KMP算法分析
    利用BURPSUITE检测CSRF漏洞
    BURPSUITE爆破密码
    动态规划—最长回文子串LEETCODE第5题深度剖析
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/14030653.html
Copyright © 2011-2022 走看看