2.20
2.20
[P1040 NOIP 2003 提高组] 加分二叉树 - 洛谷 (luogu.com.cn)
- 首先说明这是一道区间dp
- 我们可以定义\(dp[i,j]\)i结点到j结点为这根树的最大分数,那么可以考虑就是\([i,j]\)区间中存在k为根节点
- 迭代方程就为\(dp[i][j] = max(dp[i][j],dp[i][k - 1] * dp[k + 1][j] + d[k])\),注意k的取值范围
- ok,考虑到区间dp,我们迭代方向肯定就是从小往大迭代
- 然后就是初始状态了,我们考虑就是如果\(dp[i][i]\)也就是叶子结点,那么此刻值就为本身,然后\(dp[i][i+1]\)长度为2,其实值都一样,就是相加因为谁×空子树1都没意义
- 至于我们根节点,维护一个\(root[i][j]\)来存这个区间根节点即可,也需要初始化详细看代码
import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;
public class Main implements Runnable {
static StreamTokenizer cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter cout = new PrintWriter(new OutputStreamWriter(System.out));
static final int N = 35;
static int[] d = new int[N];
static int[][] dp = new int[N][N];
static int[][] root = new int[N][N];
static int n;
public static void main(String[] args) {
new Thread(null, new Main(), "", 1 << 29).start();
}
public static int nextInt() throws IOException {
cin.nextToken();
return (int) cin.nval;
}
public static void dfs(int left, int right) {
if (left > right) return;
int root_ = root[left][right];
cout.print(root_ + " ");
dfs(left, root_ - 1);
dfs(root_ + 1, right);
}
@Override
public void run() {
try {
n = nextInt();
for (int i = 1; i <= n; i++) {
d[i] = nextInt();
dp[i][i] = d[i];
root[i][i] = i;
}
for (int i = 1; i < n; i++) {
dp[i][i + 1] = d[i] + d[i + 1];
root[i][i + 1] = i;
}
for (int len = 3; len <= n; len++) {
for (int left = 1; left + len - 1 <= n; left++) {
int right = left + len - 1;
for (int k = left + 1; k < right; k++) {
if (dp[left][k - 1] * dp[k + 1][right] + d[k] > dp[left][right]) {
dp[left][right] = dp[left][k - 1] * dp[k + 1][right] + d[k];
root[left][right] = k;
}
}
}
}
cout.println(dp[1][n]);
dfs(1, n);
cout.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
P1122 最大子树和 - 洛谷 (luogu.com.cn)
- 我们定义\(dp[i]\)为以i为根节点的子树分数最大的值,相当于他只能存其根节点的值或者加上子节点权值
- 考虑到可能子节点权值为负,越加肯定越小。那么我们dfs到叶子结点时,如果它的值为负,那么它对我们没有意义,就不加即可,所以推理出转移方程\(dp[parent] += dp[son] + btf[parent](dp[son] > 0)\)
- 初始状态就dfs下去时直接设置即可
- 其实我当时觉得我们dp数组意义是不太好的,因为我们不能确定以i结点为根结点的值是否为最大和。事实确实如此例如样例中\(dp[5] = 1\),如果我们用1开是dfs的话,我就想如果从每个点都dfs一下,但是这肯定会TLE
- 随后我想到了连通图的性质,其实我们最后保留的树就是个连通图,连通图的权值和一定是一定的,应该说如果我们从连通图里的点为根进行dfs,我们根节点的dp值就是我们所求值,这里我们并不知道这个点,其实也不需要知道,我们只要随机选个点为根节点进行搜索,我们一定会搜索到连通图,而连通图连接到外面非连通图的点,总有一个点可以为连通图根结点,那么这个点的dp值即为所求
import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;
public class Main implements Runnable {
static StreamTokenizer cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter cout = new PrintWriter(new OutputStreamWriter(System.out));
static final int N = (int) (16e3 + 10);
static Vector<Integer>[] nodes = new Vector[N];
static int n;
static int[] btf = new int[N];
static int[] dp = new int[N];
public static void main(String[] args) {
new Thread(null, new Main(), "", 1 << 29).start();
}
public static int nextInt() throws IOException {
cin.nextToken();
return (int) cin.nval;
}
public static void dfs(int root, int pre) {
dp[root] = btf[root];
for (Integer son : nodes[root]) {
if (son == pre) continue;
dfs(son, root);
if (dp[son] > 0) {
dp[root] += dp[son];
}
}
}
@Override
public void run() {
try {
n = nextInt();
for (int i = 1; i <= n; i++) nodes[i] = new Vector<>();
for (int i = 1; i <= n; i++) {
btf[i] = nextInt();
}
for (int i = 1; i <= n - 1; i++) {
int a = nextInt(); int b = nextInt();
nodes[a].add(b);nodes[b].add(a);
}
dfs(1, -1);
int ans = -0x3f3f3f3f;
for (int i = 1; i <= n; i++) {
ans = Math.max(ans, dp[i]);
}
cout.println(ans);
cout.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
P2016 战略游戏 - 洛谷 (luogu.com.cn)
- 简单的树形dp,我们定义\(dp[i][1/0]\)为i结点选或者不选时士兵最少数,如果选,那么字节点选不选也没有意义,即\(dp[parent][1] += min(dp[son][1], dp[son][0])\),如果不选儿子结点就成了必选,\(dp[parent][0] += dp[son][1]\)
import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;
public class Main implements Runnable {
static StreamTokenizer cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter cout = new PrintWriter(new OutputStreamWriter(System.out));
static final int N = (int) (15e2 + 10);
static Vector<Integer>[] nodes = new Vector[N];
static int n;
static int[][] dp = new int[N][2];
public static void main(String[] args) {
new Thread(null, new Main(), "", 1 << 29).start();
}
public static int nextInt() throws IOException {
cin.nextToken();
return (int) cin.nval;
}
public static void dfs(int root, int pre) {
dp[root][1] = 1;
dp[root][0] = 0;
for (Integer son : nodes[root]) {
if (pre == son) continue;
dfs(son, root);
dp[root][1] += Math.min(dp[son][0], dp[son][1]);
dp[root][0] += dp[son][1];
}
}
@Override
public void run() {
try {
n = nextInt();
for (int i = 0; i <= n - 1; i++) nodes[i] = new Vector<>();
for (int i = 1; i <= n; i++) {
int x = nextInt(); int k = nextInt();
for (int j = 1; j <= k; j++) {
int y = nextInt();
nodes[x].add(y);
nodes[y].add(x);
}
}
for (int i = 0; i <= n - 1; i++) Arrays.fill(dp[i], 0x3f3f3f3f);
dfs(0, -1);
cout.println(Math.min(dp[0][1], dp[0][0]));
cout.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
浙公网安备 33010602011771号