2021CCPC威海H题city safety (最小割模型 or 树形dp)

传送门

题解

官方题解里已经很详细地讲了建立最小割模型,再跑网络流的做法。时间复杂度为\(O(能过)\)

主要说一下树形dp的做法,这题可以发现一个性质:如果\(i\)节点能获得\(v_p\)的收益,那么\(i\)的邻点获得的收益一定属于\(\{v_{p},v_{p + 1}, v_{p - 1}\}\)
进一步可以发现,如果\(i\)\(v_p\)的收益时,它的所有邻点可以随意从\(\{v_{p},v_{p + 1}, v_{p - 1}\}\)中取值,互相不会冲突。
于是可以设置状态:\(dp[i][j]\)表示以\(i\)为根节点的子树根节点取得\(v_j\)收益时,整棵子树的最大收益。
于是很容易得到转移方程:

\[dp[i][j] += max\{dp[son_i][j], dp[son_i][j - 1], dp[son_i][j + 1]\} \]

dp代码

/*************************************************************************
> File Name: 1.cpp
> Author: Knowledge_llz
> Mail: 925538513@qq.com
> Blog: https://www.cnblogs.com/Knowledge-Pig/ 
************************************************************************/

#include<bits/stdc++.h>
#define LL long long
#define endl '\n'
using namespace std;
const int maxx = 2e5 + 10;
int n, w[maxx], v[maxx], dp[250][250];
vector<int> vec[maxx];
void dfs(int id, int fa){
    for(int i = 1; i <= n; ++i) dp[id][i] = v[i] - w[id];
    for(auto u : vec[id]){
        if(u == fa) continue;
        dfs(u, id);
        for(int i = 1; i < n; ++i)
            dp[id][i] += max({dp[u][i - 1], dp[u][i], dp[u][i + 1]});
        dp[id][0] += max(dp[u][0], dp[u][1]);
        dp[id][n] += max(dp[u][n], dp[u][n - 1]);
    }
}
int main(){
    ios::sync_with_stdio(false); cin.tie(0);
#ifndef ONLINE_JUDGE
    freopen("input.in", "r", stdin);
    freopen("output.out","w", stdout);
#endif
    cin >> n;
    for(int i = 1; i <= n; ++i) cin >> w[i];
    for(int i = 1; i <= n; ++i) cin >> v[i];
    for(int i = 1, u, v; i < n; ++i){
        cin >> u >> v;
        vec[u].push_back(v);
        vec[v].push_back(u);
    }
    dfs(1, 0);
    int ans = 0;
    for(int i = 0; i <= n; ++i) ans = max(ans, dp[1][i]);
    cout << ans << endl;
    return 0;
}

网络流代码

/*************************************************************************
> File Name: 1.cpp
> Author: Knowledge_llz
> Mail: 925538513@qq.com
> Blog: https://www.cnblogs.com/Knowledge-Pig/ 
************************************************************************/

#include<bits/stdc++.h>
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define LL long long
#define pb push_back
#define fi first
#define se second
#define pr pair<int,int>
#define mk(a,b) make_pair(a,b)
#define endl '\n'
using namespace std;
const int maxx = 2e5 + 10, inf = 1e9;
int n, be[maxx], ne[maxx * 10], to[maxx * 10], w[maxx * 10], dep[maxx], cost[maxx], v[maxx], now[maxx], e = 1;
int s = maxx - 10, t = maxx - 11, cnt;
vector<int> vec[250], dis[250][250];
void add(int x, int y, int z, bool p){
	to[++e] = y;
	ne[e] = be[x];
	be[x] = e;
	w[e] = z;
	if(p) add(y, x, 0, 0);
}
void dfs(int rt, int id, int fa, int deep){
	dis[rt][deep].push_back(id);
	for(auto u : vec[id]) if(u != fa) dfs(rt, u, id, deep + 1);
}
bool bfs(){
	queue<int> q;
	dep[t] = 0;
	for(int i = 1; i <= cnt; ++i) dep[i] = 0;
	q.push(s); 
	dep[s] = 1; now[s] = be[s];
	while(!q.empty()){
		int id = q.front(); q.pop();
		for(int i = be[id]; i; i = ne[i]){
			int u = to[i];
			if(!dep[u] && w[i] > 0){
				dep[u] = dep[id] + 1;
				now[u] = be[u];
				q.push(u);
			}
		}
	}
	return dep[t] > 0;
}
int dfs(int id, int mini){
	if(id == t || !mini) return mini;
	int flow, ret = 0;
	for(int &i = now[id]; i; i = ne[i]){
		int go = to[i];
		if(w[i] > 0 && dep[go] == dep[id] + 1){
			flow = dfs(go, min(mini, w[i]));
			if(!flow) dep[go] = inf;
			w[i] -= flow;
			w[i ^ 1] += flow;
			ret += flow;
			mini -= flow;
		}
		if(!mini) return ret;
	}
	return ret;
}
int dinic(){
	int ans = 0, tmp;
	while(bfs()){
		tmp = dfs(s, inf);
		if(!tmp) break;
		ans += tmp;
	}
	return ans;
}
int main(){
	ios::sync_with_stdio(false); cin.tie(0);
#ifndef ONLINE_JUDGE
	freopen("input.in", "r", stdin);
	freopen("output.out","w", stdout);
#endif
	cin >> n;
	for(int i = 1; i <= n; ++i){  cin >> cost[i];  add(i, t, cost[i], 1); }
	for(int i = 1; i <= n; ++i) cin >> v[i];
	for(int i = 1, u, v; i < n; ++i){
		cin >> u >> v;
		vec[u].push_back(v);
		vec[v].push_back(u);
	}
	for(int i = 1; i <= n; ++i) dfs(i, i, 0, 1);
	cnt = n; int  ans = v[n] * n;
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= n; ++j){
			++cnt;
			add(s, cnt, v[j] - v[j - 1], 1);
			if(j > 1) add(cnt, cnt - 1, inf, 1);
			for(auto u : dis[i][j]) add(cnt, u, inf, 1);
		}
	cout << ans - dinic() << endl;

return 0;
}
posted @ 2021-11-25 19:32  Knowledge-Pig  阅读(423)  评论(3编辑  收藏  举报