喜欢数学的wlswls最近被萎住了。
现在他一共有1...n1...n这么多数字,取数字ii会得到f[i]f[i]的收益。数字之间有些边,对于所有的i(i != 1)i(i!=1),若ii为奇数,则ii与3i+13i+1之间有边,否则ii与i/2i/2之间有边。如果一条边的两个顶点xyxy都被取了,那么会失去d[min(x, y)]d[min(x,y)]的价值。请问wlswls怎么取,才能使得收益最大?
输入描述
第一行一个整数nn。
接下来一行nn个整数表示ff。
接下来一行nn个整数表示dd。
1 \leq n \leq 1001≤n≤100
1 \leq f[i], d[i] \leq 10001≤f[i],d[i]≤1000
输出描述
输出一个整数表示答案。
样例输入 1
2 10 10 1 2样例输出 1
19dp[maxn][2]。表示在第i个点选取和不选取的最大值。
这里的并查集有点区别,这里相当于把每个集合整体连接到0节点。
注意连边。
#include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> #include<string> #include<queue> #define PI 3.1415926 #define zero(x) (((x)>0?(x):-(x))<eps) using namespace std; typedef long long ll; const double eps = 1e-8; const int maxn = 110; int dp[maxn][2];//第二维 0代表没选 1代表选取 int f[maxn], d[maxn]; vector<int>vec[maxn]; int pre[maxn]; int find(int x) { if (pre[x] == 0) { return x; } else { return pre[x] = find(pre[x]); } } void join(int x, int y) { int fx = find(x); int fy = find(y); if (fx != fy) { pre[fx] = fy; } } void dfs(int u, int fa) { dp[u][0] = 0, dp[u][1] = f[u]; for (int i = 0; i < vec[u].size(); i++) { int v = vec[u][i]; if (v == fa) continue; dfs(v, u); dp[u][0] += max(dp[v][0], dp[v][1]); dp[u][1] += max(dp[v][0], dp[v][1] - d[min(u, v)]); } } int main() { //freopen("C:/input.txt", "r", stdin); int n; scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &f[i]); for (int i = 1; i <= n; i++) scanf("%d", &d[i]); for (int i = 2; i <= n; i++) { if (i & 1) //qishu { if (3 * i + 1 <= n) { vec[3 * i + 1].push_back(i); vec[i].push_back(3 * i + 1); join(3 * i + 1, i); } } else { vec[i].push_back(i / 2); vec[i / 2].push_back(i); join(i, i / 2); } } for (int i = 1; i <= n; i++) { if (!pre[i]) { vec[0].push_back(i); vec[i].push_back(0); } } dfs(0, 0); printf("%d\n", dp[0][0]); return 0; }
CCPC-Wannafly Winter Camp Day1 (Div2, onsite) E 流流流动 树形DP
最新推荐文章于 2020-08-24 21:24:46 发布