最小割 ---- 2021 ccpc 威海 H city-safety(最大利润 = 最大收益 - 最小花费(最小割))

news/2024/7/2 23:39:03

题目链接


题目大意:

一棵树,加强第 iii 个点有 wiw_iwi 的花费,而如果距离某
个点 ≤p≤ pp 的所有点都加强了,则会有 vpv_pvp 的收益,求最大净收益。


解题思路:

树形dp做法想不明白为啥是对的??qwq
大佬的代码仅供参考,有看懂的聚聚留言qwq

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;int main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int n;cin >> n;vector<int> a(n), b(n);for(int i = 0; i < n; ++i) cin >> a[i];for(int i = 0; i < n; ++i) cin >> b[i];vector<vector<int>> g(n);for(int i = 1; i < n; ++i) {int u, v;cin >> u >> v;--u, --v;g[u].push_back(v);g[v].push_back(u);}vector<vector<int>> dp(n, vector<int>(n + 1, -1e9));function<void(int,int)> dfs = [&](int u, int fa) {dp[u][0] = 0;for(int i = 1; i <= n; ++i) {dp[u][i] = b[i - 1] - a[u];}for(int v : g[u]) {if(v == fa) continue;dfs(v, u);vector<int> ndp(n + 1, -1e9);for(int q = 0; q <= n; ++q) {// dp[u][q]: 和 u 距离小于 q 的点都被选择了// 那么对于 v 来说,和 v 距离小于 q - 1 的点显然必须被选择for(int p = max(0, q - 1); p <= min(n, q + 1); ++p) {if(1) ndp[q] = max(ndp[q], dp[v][p] + dp[u][q]);else ndp[q] = max(ndp[q],dp[u][q]);}}dp[u] = ndp;}};dfs(0, -1);cout << *max_element(dp[0].begin(), dp[0].end()) << '\n';
}

最小割模型

首先我们先把所有的收益全部加上去。现在就是要花费最小?
我们看n=200n=200n=200非常小,可以往网络流方向想,因为要花费最小,那么可以转成最小割去求

  • 左边的点 vi,pv_{i,p}vi,p 表示距离第 iii 个点 ≤p≤ pp 的所有点全选
  • 右边的点 uiuiui 表示原图的点 iii
  • 源点连向每个 vi,pv_{i,p}vi,p,容量为增量收益 vi,p−vi,p−1v_{i,p} − v_{i,p−1}vi,pvi,p1,割掉这条边表示放弃这个增量收益
  • 每个 vi,pv_{i,p}vi,p 连向右边距离 iiippp 的点,容量为无穷大
  • 每个 vi,pv_{i,p}vi,p 连向 vi,p−1v_{i,p−1}vi,p1,容量为无穷大,这样使得 vi,pv_{i,p}vi,p 间接连
  • 向与 iii 距离 <p< p<p 的点,用来限制放弃收益必须按 ppp 从大到小放弃
  • 右边每个点连向汇点,容量为选这个点的代价,割掉这条边
    表示付出这个点的代价
  • 答案减去最小割。

AC code

#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = 6e6 + 10;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {x = 0;char ch = getchar();ll f = 1;while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {read(first);read(args...);
}int n, m, s, t;
struct node {int to, nxt, len;
}e[maxn];int head[maxn], cnt;inline void add(int from, int to, int len) {e[cnt] = {to,head[from],len};head[from] = cnt ++;e[cnt] = {from,head[to],0};head[to] = cnt ++;
}int d[maxn], cur[maxn];bool bfs() {ms(d,0);queue<int> q;q.push(s);d[s] = 1;while(!q.empty()) {int u = q.front();q.pop();for(int i = head[u]; ~i; i = e[i].nxt) {int v = e[i].to;if(d[v] || e[i].len <= 0) continue;q.push(v);d[v] = d[u] + 1; }}for(int i = 0; i <= t; ++ i) cur[i] = head[i];return d[t] != 0;
}int dfs(int u, int flow) {if(u == t) return flow;for(int &i = cur[u]; ~i; i = e[i].nxt) {int v = e[i].to;if(d[u] + 1 != d[v] || e[i].len <= 0) continue;int delta = dfs(v,min(flow,e[i].len));if(delta <= 0) continue;e[i].len -= delta;e[i^1].len += delta;return delta;}return 0;
}inline ll get_maxflow() {ll maxflow = 0, delta = 0;while(bfs()) {while(delta = dfs(s,INF)) {maxflow += delta;}}return maxflow;
}int w[202], v[202];
int G[202][202];
int poiidx[202];
int vipidx[202][202];
int idx;
int main() {IOS;ms(G,INF);ms(head,-1);cin >> n;for(int i = 1; i <= n; ++ i) cin >> w[i], G[i][i] = 0;for(int i = 0; i < n; ++ i) cin >> v[i];for(int i = 1; i < n; ++ i) {int u, v;cin >> u >> v;G[u][v] = G[v][u] = 1; }for(int k = 1; k <= n; ++ k)for(int i = 1; i <= n; ++ i)for(int j = 1; j <= n; ++ j)G[i][j] = min(G[i][k]+G[k][j],G[i][j]);s = 0;for(int i = 1; i <= n; ++ i) poiidx[i] = ++ idx;for(int i = 1; i <= n; ++ i) for(int p = 0; p < n; ++ p)vipidx[i][p] = ++ idx;t = ++ idx;for(int i = 1; i <= n; ++ i)for(int p = 0; p < n; ++ p) {add(s,vipidx[i][p],p?(v[p]-v[p-1]):(v[p]));if(p!=0) add(vipidx[i][p],vipidx[i][p-1],INF);} for(int i = 1; i <= n; ++ i) add(poiidx[i],t,w[i]);for(int i = 1; i <= n; ++ i) for(int j = 1; j <= n; ++ j) {int dist = G[i][j];add(vipidx[i][dist],poiidx[j],INF);}int ans = n*v[n-1];cout << ans - get_maxflow();return 0; 
}

http://lihuaxi.xjx100.cn/news/285828.html

相关文章

Playboy封面女郎、互联网第一夫人,程序员们的“钢铁审美”

整理 | 琥珀 出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09; 46 年前&#xff0c;《花花公子》&#xff08;Playboy&#xff09;的一期杂志封面女郎 Lenna&#xff0c;成为数万“钢铁直男”的梦中女神。然而&#xff0c;这位女性更为人所知的是她在计算机图像处理领…

java自动装箱性能

2019独角兽企业重金招聘Python工程师标准>>> Java 的基本数据类型&#xff08;int、double、 char&#xff09;都不是对象。但由于很多Java代码需要处理的是对象&#xff08;Object&#xff09;&#xff0c;Java给所有基本类型提供了包装类&#xff08;Integer、Dou…

[NC16591]关押罪犯 并查集

题解&#xff1a;很明显的并查集&#xff0c;但因为它们带有权值&#xff0c;所以我们先要把他排序&#xff0c;我们要尽可能让危害大的罪犯在两个监狱里&#xff08;这里有一点贪心的味道&#xff09;。 1.首先我们把它门按照之间的影响值从大到小排序。 2.假设a与b是敌人&…

简单分析MySQL 一则慢日志监控误报问题

这篇文章主要介绍了MySQL 一则慢日志监控误报的问题分析与解决&#xff0c;帮助大家更好的理解和使用MySQL&#xff0c;感兴趣的朋友可以了解下 之前因为各种原因&#xff0c;有些报警没有引起重视&#xff0c;最近放假马上排除了一些潜在的人为原因&#xff0c;发现数据库的慢…

一直在努力的你是否也是这样的(经典语录总结)

1.下次再遇见喜欢的人&#xff0c;一定要提醒自己&#xff0c;只做朋友&#xff0c;只谈笑风生&#xff0c;不可以动情&#xff0c;不远不近的欣赏&#xff0c;淡淡的喜欢&#xff0c;不至于最后乱了初心&#xff0c;败了芳华。 ——杨绛 2.走好选择的路&#xff0c;别选择好走…

前缀和 + ST表 ---- CF 1556 E. Equilibrium(两个序列 + - 操作使得每位相等) 详解

题目连接 题目大意&#xff1a; 就是给你两个长度为nnn的a,ba,ba,b数组&#xff0c;给你q∈[1,1e5]q\in[1,1e5]q∈[1,1e5]次询问&#xff0c;每次询问一个区间[l,r][l,r][l,r] 你对这个区间里面的数可以进行一下操作 取出偶数个位置 l≤pos1<pos2<....<posz≤r∣[z%…

手写 30 个主流机器学习算法,代码超 3 万行,全都开源了!

点击上方“视学算法”&#xff0c;选择“星标”公众号第一时间获取价值内容本文经机器之心&#xff08;ID&#xff1a;almosthuman2014&#xff09;授权转载&#xff0c;禁二次转载参与&#xff1a;思源、一鸣、张倩用 NumPy 手写所有主流 ML 模型&#xff0c;普林斯顿博士后 D…

赵本山:我的时代还没有结束 | Python告诉你

作者 | 丁彦军来源 | 恋习Python&#xff08;ID: sldata2017&#xff09;【AI科技大本营按】今年春晚的小品好看吗&#xff1f;没有了赵本山的春晚总觉得少了点什么&#xff0c;然而许久不登春晚舞台的本山大叔借着B站的东风证明了「你大爷还是你大爷」。最近很多人被“改革春…