zoukankan      html  css  js  c++  java
  • 「树上背包」可怜与超市

    可怜与超市

    发现商品间的关系显然是棵树,所以做树上背包。

    发现商品的价格都很高不能放在状态里,而价值都是1,所以转换维度。

    定义(dp[u][j][0/1])为在(u)的子树中选出(j)个物品所需要的最小价格,其中0代表不用优惠券买u,1代表用优惠券买u。

    转移:

    [sum_{j = 0}^{siz[u] - siz[v]} ]

    [sum_{k = 0}^{siz[v]} ]

    [dp[u][j + k][1] = min(dp[u][j + k][1], dp[u][j][1] + min(dp[v][k][1], dp[v][k][0])) ]

    [dp[u][j + k][0] = min(dp[u][j + k][0], dp[u][j][0] + dp[v][k][0]) ]

    答案为 (max(i)) 满足 (dp[1][i][1] <= b)

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <iostream>
    using namespace std;
    char buf[1 << 20], *p1 = buf, *p2 = buf;
    char getc() {
        if (p1 == p2) {
    	p1 = buf, p2 = buf + fread(buf, 1, 1 << 20, stdin);
    	if (p1 == p2) return EOF;
        }
        return *p1++;
    }
    inline int read() {
        int s = 0, w = 1;
        char c = getc();
        while (c < '0' || c > '9') { if (c == '-') w = -1; c = getc(); }
        while (c >= '0' && c <= '9') s = s * 10 + c - '0', c = getc();
        return s * w;
    }
    const int maxn = 5e3 + 5;
    int n, B;
    struct edge {
        int nex, to;
    }e[maxn * maxn];
    int head[maxn], tot;
    void Add(int u, int v) {
        e[++tot] = (edge) { head[u], v };
        head[u] = tot;
    }
    int dp[maxn][maxn][3];
    int siz[maxn], c[maxn], d[maxn];
    void Dfs(int u) {
        siz[u] = 1;
        for (int i = head[u]; i; i = e[i].nex) {
    	int v = e[i].to;
    	Dfs(v);
    	siz[u] += siz[v];
        }
        return;
    }
    void DP(int u) {
        for (int i = head[u]; i; i = e[i].nex) {
    	int v = e[i].to;
    	DP(v);
    	for (int j = siz[u] - siz[v]; j >= 0; j--) {
    	    for (int k = siz[v]; k >= 0; k--) {
    		dp[u][j + k][1] = min(dp[u][j + k][1], dp[u][j][1] + min(dp[v][k][1], dp[v][k][0]));
    		dp[u][j + k][0] = min(dp[u][j + k][0], dp[u][j][0] + dp[v][k][0]);
    	    }
    	}
        }
    }
    int main() {
        n = read(), B = read();
        int fa;
        for (int i = 1; i <= n; i++) {
    	if (i == 1) {
    	    c[i] = read();
    	    d[i] = read();
    	}
    	else {
    	    c[i] = read();
    	    d[i] = read();
    	    fa = read();
    	    Add(fa, i);
    	}
        }
        Dfs(1);
        memset(dp, 0x3f, sizeof dp);
        for (int i = 1; i <= n; i++) {
    	dp[i][1][1] = c[i] - d[i];
    	dp[i][1][0] = c[i];
    	dp[i][0][0] = 0;
        }
        DP(1);
        int ans;
        for (int i = 1; i <= n; i++) {
    	if (dp[1][i][1] <= B)
    	    ans = i;
        }
        printf("%d
    ", ans);
        return 0;
    }
    

    另外,两个DFS可以合起来写,这样就相当于一次枚举一条边的两个端点,从各自的子树中去选择。

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <iostream>
    using namespace std;
    char buf[1 << 20], *p1 = buf, *p2 = buf;
    char getc() {
        if (p1 == p2) {
    	p1 = buf, p2 = buf + fread(buf, 1, 1 << 20, stdin);
    	if (p1 == p2) return EOF;
        }
        return *p1++;
    }
    inline int read() {
        int s = 0, w = 1;
        char c = getc();
        while (c < '0' || c > '9') { if (c == '-') w = -1; c = getc(); }
        while (c >= '0' && c <= '9') s = s * 10 + c - '0', c = getc();
        return s * w;
    }
    const int maxn = 5e3 + 5;
    int n, B;
    struct edge {
        int nex, to;
    }e[maxn * maxn];
    int head[maxn], tot;
    void Add(int u, int v) {
        e[++tot] = (edge) { head[u], v };
        head[u] = tot;
    }
    int dp[maxn][maxn][3];
    int siz[maxn], c[maxn], d[maxn];
    void DP(int u) {
        siz[u] = 1;
        for (int i = head[u]; i; i = e[i].nex) {
    	int v = e[i].to;
    	DP(v);
    	for (int j = siz[u]; j >= 0; j--) {
    	    for (int k = siz[v]; k >= 0; k--) {
    		dp[u][j + k][1] = min(dp[u][j + k][1], dp[u][j][1] + min(dp[v][k][1], dp[v][k][0]));
    		dp[u][j + k][0] = min(dp[u][j + k][0], dp[u][j][0] + dp[v][k][0]);
    	    }
    	}
    	siz[u] += siz[v];
        }
    }
    int main() {
        n = read(), B = read();
        int fa;
        for (int i = 1; i <= n; i++) {
    	if (i == 1) {
    	    c[i] = read();
    	    d[i] = read();
    	}
    	else {
    	    c[i] = read();
    	    d[i] = read();
    	    fa = read();
    	    Add(fa, i);
    	}
        }
        //Dfs(1);
        memset(dp, 0x3f, sizeof dp);
        for (int i = 1; i <= n; i++) {
    	dp[i][1][1] = c[i] - d[i];
    	dp[i][1][0] = c[i];
    	dp[i][0][0] = 0;
        }
        DP(1);
        int ans;
        for (int i = 1; i <= n; i++) {
    	if (dp[1][i][1] <= B)
    	    ans = i;
        }
        printf("%d
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    Spring 理解和开始
    SpringBoot之日期时间格式化
    Java 中 DO、PO、BO、DTO、VO 等各对象概念说明
    RocketMQ之Broker
    RocketMQ之NameSever
    RocketMQ之Consumer
    RocketMQ之Producer
    RocketMQ之简单使用
    RocketMQ单机版安装
    RocketMQ介绍
  • 原文地址:https://www.cnblogs.com/Zfio/p/13726289.html
Copyright © 2011-2022 走看看