zoukankan      html  css  js  c++  java
  • BZOJ 1812: [Ioi2005]riv( 树形dp )

    树背包, 左儿子右兄弟来表示树, dp(x, y, z)表示结点x, x的子树及x的部分兄弟共建y个伐木场, 离x最近的伐木场是z时的最小代价. 时间复杂度O(N^2*K^2)

    -------------------------------------------------------------------------

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
     
    using namespace std;
     
    const int maxn = 109;
    const int INF = 2000000009;
     
    int N, K;
    int w[maxn], d[maxn];
    int dp[maxn][59][maxn];
     
    inline void Min(int &x, int t) {
    if(t < x) x = t;
    }
     
    struct Node {
    Node *lc, *rc;
    int n;
    } pool[maxn], *pt = pool, *V[maxn];
     
    inline void Add(int u, int v) {
    if(V[u]->lc) {
    V[v]->rc = V[u]->lc;
    V[u]->lc = V[v];
    } else
    V[u]->lc = V[v];
    }
     
    void dfsDist(Node* t, int D = 0) {
    d[t->n] += D;
    if(t->lc) dfsDist(t->lc, d[t->n]);
    if(t->rc) dfsDist(t->rc, D);
    }
     
    int dfs(int x, int y, int z) {
    int &ret = dp[x][y][z];
    if(~ret) return ret;
    ret = INF;
    int con = w[x] * (d[x] - d[z]);
    if(!V[x]->lc) {
    if(!V[x]->rc) {
    if(!y) return ret = con;
    if(y == 1) return ret = 0;
    return ret;
    }
    for(int i = 0; i <= y; i++) {
    if(dfs(V[x]->rc->n, i, z) < INF)
    Min(ret, dfs(V[x]->rc->n, i, z) + con);
    if(i) Min(ret, dfs(V[x]->rc->n, i - 1, z));
    }
    return ret;
    }
    int ch = V[x]->lc->n;
    if(!V[x]->rc) {
    for(int i = 0; i <= y; i++) {
    if(dfs(ch, i, z) < INF)
    Min(ret, dfs(ch, i, z) + con);
    if(i) Min(ret, dfs(ch, i - 1, x));
    }
    return ret;
    }
    int bro = V[x]->rc->n;
    for(int i = 0; i <= y; i++) {
    if(dfs(ch, i, z) < INF && dfs(bro, y - i, z) < INF)
    Min(ret, dfs(ch, i, z) + dfs(bro, y - i, z) + con);
    if(i && dfs(ch, i - 1, x) < INF && dfs(bro, y - i, z) < INF)
    Min(ret, dfs(ch, i - 1, x) + dfs(bro, y - i, z));
    }
    return ret;
    }
     
    int main() {
    scanf("%d%d", &N, &K);
    for(int i = 0; i <= N; i++)
    pt->lc = pt->rc = NULL, pt->n = i, V[i] = pt++;
    for(int i = 1, t; i <= N; i++) {
    scanf("%d%d%d", w + i, &t, d + i);
    Add(t, i);
    }
    dfsDist(V[0]);
    memset(dp, -1, sizeof dp);
    printf("%d ", dfs(0, K, 0));
    return 0;
    }

    -------------------------------------------------------------------------

    1812: [Ioi2005]riv

    Time Limit: 10 Sec  Memory Limit: 64 MB
    Submit: 366  Solved: 199
    [Submit][Status][Discuss]

    Description

    几乎整个Byteland王国都被森林和河流所覆盖。小点的河汇聚到一起,形成了稍大点的河。就这样,所有的河水都汇聚并流进了一条大河,最后这条大河流进了大海。这条大河的入海口处有一个村庄——名叫Bytetown 在Byteland国,有n个伐木的村庄,这些村庄都座落在河边。目前在Bytetown,有一个巨大的伐木场,它处理着全国砍下的所有木料。木料被砍下后,顺着河流而被运到Bytetown的伐木场。Byteland的国王决定,为了减少运输木料的费用,再额外地建造k个伐木场。这k个伐木场将被建在其他村庄里。这些伐木场建造后,木料就不用都被送到Bytetown了,它们可以在 运输过程中第一个碰到的新伐木场被处理。显然,如果伐木场座落的那个村子就不用再付运送木料的费用了。它们可以直接被本村的伐木场处理。 注意:所有的河流都不会分叉,也就是说,每一个村子,顺流而下都只有一条路——到bytetown。 国王的大臣计算出了每个村子每年要产多少木料,你的任务是决定在哪些村子建设伐木场能获得最小的运费。其中运费的计算方法为:每一块木料每千米1分钱。 编一个程序: 1.从文件读入村子的个数,另外要建设的伐木场的数目,每年每个村子产的木料的块数以及河流的描述。 2.计算最小的运费并输出。

    Input

    第一行 包括两个数 n(2<=n<=100),k(1<=k<=50,且 k<=n)。n为村庄数,k为要建的伐木场的数目。除了bytetown外,每个村子依次被命名为1,2,3……n,bytetown被命名为0。 接下来n行,每行包涵3个整数 wi——每年i村子产的木料的块数 (0<=wi<=10000) vi——离i村子下游最近的村子(或bytetown)(0<=vi<=n) di——vi到i的距离(km)。(1<=di<=10000) 保证每年所有的木料流到bytetown的运费不超过2000,000,000分 50%的数据中n不超过20。

    Output

    输出最小花费,精确到分。

    Sample Input

    4 2
    1 0 1
    1 1 10
    10 2 5
    1 2 3

    Sample Output

    4

    HINT

    Source

  • 相关阅读:
    极限编程(XP)基本原则与规范
    Displaying Alerts with UIAlertView
    Objective-C Basic
    Cocos2D Study
    DynamoDB Local for Desktop Development
    图解centos7如何关闭ipv6仅使用ipv4
    MySQL中的配置参数interactive_timeout和wait_timeout(可能导致过多sleep进程的两个参数)
    被mysql中的wait_timeout坑了
    linux:解决SSH连接Linux超时自动断开
    zookeeper-3.5.5安装报错:找不到或无法加载主类 org.apache.zookeeper.server.quorum.QuorumPeerMain
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/5175356.html
Copyright © 2011-2022 走看看