• [poj 2152] fire (树形dp)


    Time Limit: 2000MS Memory Limit: 65536K
    Description

    Country Z has N cities, which are numbered from 1 to N. Cities are connected by highways, and there is exact one path between two different cities. Recently country Z often caught fire, so the government decided to build some firehouses in some cities. Build a firehouse in city K cost W(K). W for different cities may be different. If there is not firehouse in city K, the distance between it and the nearest city which has a firehouse, can’t be more than D(K). D for different cities also may be different. To save money, the government wants you to calculate the minimum cost to build firehouses.
    Input

    The first line of input contains a single integer T representing the number of test cases. The following T blocks each represents a test case.

    The first line of each block contains an integer N (1 < N <= 1000). The second line contains N numbers separated by one or more blanks. The I-th number means W(I) (0 < W(I) <= 10000). The third line contains N numbers separated by one or more blanks. The I-th number means D(I) (0 <= D(I) <= 10000). The following N-1 lines each contains three integers u, v, L (1 <= u, v <= N,0 < L <= 1000), which means there is a highway between city u and v of length L.
    Output

    For each test case output the minimum cost on a single line.
    Sample Input

    5
    5
    1 1 1 1 1
    1 1 1 1 1
    1 2 1
    2 3 1
    3 4 1
    4 5 1
    5
    1 1 1 1 1
    2 1 1 1 2
    1 2 1
    2 3 1
    3 4 1
    4 5 1
    5
    1 1 3 1 1
    2 1 1 1 2
    1 2 1
    2 3 1
    3 4 1
    4 5 1
    4
    2 1 1 1
    3 4 3 2
    1 2 3
    1 3 3
    1 4 2
    4
    4 1 1 1
    3 4 3 2
    1 2 3
    1 3 3
    1 4 2
    Sample Output
    2
    1
    2
    2
    3

    很好的树形dp~
    f[u][i] 表示u点及其子树的所有节点都被保护且i来保护u的最优值
    ans[i] 表示i及其子树所有节点都被保护的最优值
    那么显然ans[i]=min(ans[i],f[i][j]) (1<=j<=n)
    思路:
    显然是从叶节点不断向上更新至根 则最后结果为ans[1]
    要求一个节点(u)的ans值那么就要求出所有f[u][i] (1<=i<=n) 取min ,
    那么对于其中一种情况 要求f[u][i] 时(u、i值固定),需要遍历所有u的子节点并把所有子节点影响u的最小花费(可能是原来它对应的ans,也可能是如果选i点那么i点可以一举两得使一个cost[i]保护多个点并且优于取ans)加和 再加上cost[i]
    出错(我第一次写时犯的错qwq 各种脑残233):
    在dfs中遍历u所有节点时把’j’写成了‘i’(代码中有标注),还查了将近半个小时
    ヽ(`Д´)ノ︵ ┻━┻ ┻━┻

    code:

    //By Menteur_Hxy
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    using namespace std;
    
    const int MAX=1010;
    const int INF=0x3f3f3f3f;
    int n,cnt;
    int cost[MAX],d[MAX],head[MAX],dis[MAX][MAX],dp[MAX][MAX],ans[MAX];
    
    int rd() {
        int x=0;
        char c=' ';
        while(c==' ' || c=='
    ') c=getchar();
        while(c<='9'&&c>='0') {
            x=x*10+c-'0';
            c=getchar();
        }
        return x;
    }
    
    struct edges{
        int to,next,dis;
        void add(int a,int b,int c) {
            to=b,next=head[a],dis=c,head[a]=cnt;
        }
    }edge[MAX<<1];
    
    queue <int> q;
    
    void getd(int dis[],int s) {
        dis[s]=0;
        q.push(s);
        while(!q.empty()) {
            int u=q.front(); q.pop();
            for(int i=head[u];i;i=edge[i].next) {
                int v=edge[i].to;
                if(!dis[v] && v!=s) {
                    dis[v]=dis[u]+edge[i].dis;
                    q.push(v);
                }
            }
        }
    }
    
    void dfs(int u,int fa) {
        for(int i=head[u];i;i=edge[i].next) 
            if(edge[i].to!=fa) dfs(edge[i].to,u);
    
        for(int i=1;i<=n;i++) {
            if(dis[u][i]<=d[u]) {
                int tmp=0;
                for(int j=head[u];j;j=edge[j].next) {
                    int v=edge[j].to;//出错处233 j写成i
                    if(v!=fa) tmp+=min(ans[v],dp[v][i]-cost[i]);
                }
                dp[u][i]=tmp+cost[i];
            }
            else dp[u][i]=INF;
        }
        for(int i=1;i<=n;i++) ans[u]=min(ans[u],dp[u][i]);
    }
    
    void init() {
        cnt=0;
        memset(head,0,sizeof head);
        memset(ans,0x3f,sizeof ans);
        memset(dp,0,sizeof dp);
        memset(dis,0,sizeof dis);
    }
    
    int main() {
        int T=rd();
        while(T--) {
            init();
            n=rd();
            for(int i=1;i<=n;i++) cost[i]=rd();
            for(int i=1;i<=n;i++) d[i]=rd();
            for(int i=1;i<n;i++) {
                int a=rd(),b=rd(),c=rd();
                edge[++cnt].add(a,b,c);
                edge[++cnt].add(b,a,c);
            }
            for(int i=1;i<=n;i++) getd(dis[i],i);
            dfs(1,-1);
            printf("%d
    ",ans[1]);
        }
        return 0;
    }
    版权声明:本文为博主原创文章,未经博主允许不得转载。 博主:https://www.cnblogs.com/Menteur-Hxy/
  • 相关阅读:
    android平台从froyo 2.2开始支持jni单步调试
    Ubuntu java 环境变量
    ubuntu 10.04安装sunjava5jdk
    proc文件系统usb部分信息输出
    Linux lftp乱码解决及使用书签的方法
    用find & grep查找文件内容
    ubuntu10.10 下安装android 2.2开发环境
    VIM复制粘贴大全!
    kinect 无法在我的android开发板上显示的分析
    hdu 1087 Super Jumping! Jumping! Jumping!
  • 原文地址:https://www.cnblogs.com/Menteur-Hxy/p/9247999.html
Copyright © 2020-2023  润新知