zoukankan      html  css  js  c++  java
  • poj2152 Fire(树形DP)

    题目链接:https://vjudge.net/problem/POJ-2152

    题意:给定一颗大小为n的树,在每个结点建消防站花费为w[i],如果某结点没有消防站,只要在它距离<=d[i]的结点有消防站即可,求最小花费。

    思路:

      好难的树形dp,一点思绪也木有,只能搜题解。

      用dp[u][i]表示以u为根的子树满足条件,并且结点u依赖于结点i的最小花费。用best[u]表示以u根的子树满足条件的最小花费,那么best[u]=min(dp[u][i])。

      求best[u]时,先跑一遍dfs得到所有结点距离u的距离dis[i]。如果dis[i]>d[u],那么u没法依赖i,此时dp[u][i]=inf。否则dis[i]<=d[u],此时dp[u][i]=w[i]+sum( min( best[v] , dp[v][i]-w[i] ) ),其中i从1遍历到n,v是u的子结点。因为v的依赖有两种情况,如果v依赖于以v为根的子树中的结点,即best[v]; 如果v依赖于其余的结点,那么一定是i。反证一下,如果v依赖于k,那么u也一定依赖于k。所以应取best[v]和dp[v][i]-w[i]的最小值,减w[i]是因为w[i]多加了一次。

    AC代码:

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    
    const int maxn=1e3+5;
    const int inf=0x3f3f3f3f;
    int T,n,cnt,head[maxn],w[maxn],d[maxn],dp[maxn][maxn],dis[maxn];
    int best[maxn];
    
    struct node{
        int v,w,nex;
    }edge[maxn<<1];
    
    void adde(int u,int v,int w){
        edge[++cnt].v=v;
        edge[cnt].w=w;
        edge[cnt].nex=head[u];
        head[u]=cnt;
    }
    
    void getdis(int u,int fa,int len){
        dis[u]=len;
        for(int i=head[u];i;i=edge[i].nex){
            int v=edge[i].v;
            if(v==fa) continue;
            getdis(v,u,len+edge[i].w);
        }
    }
    
    void dfs(int u,int fa){
        for(int i=head[u];i;i=edge[i].nex){
            int v=edge[i].v;
            if(v==fa) continue;
            dfs(v,u);
        }
        getdis(u,0,0);
        best[u]=inf;
        for(int i=1;i<=n;++i){
            if(dis[i]>d[u]) dp[u][i]=inf;
            else{
                dp[u][i]=w[i];
                for(int j=head[u];j;j=edge[j].nex){
                    int v=edge[j].v;
                    if(v==fa) continue;
                    dp[u][i]+=min(best[v],dp[v][i]-w[i]);
                }
            }
            best[u]=min(best[u],dp[u][i]);
        }
    }
    
    int main(){
        scanf("%d",&T);
        while(T--){
            scanf("%d",&n);
            cnt=0;
            for(int i=1;i<=n;++i)
                head[i]=0;
            for(int i=1;i<=n;++i)
                scanf("%d",&w[i]);
            for(int i=1;i<=n;++i)
                scanf("%d",&d[i]);
            for(int i=1;i<n;++i){
                int u,v,w;
                scanf("%d%d%d",&u,&v,&w);
                adde(u,v,w);
                adde(v,u,w);
            }
            dfs(1,0);
            printf("%d
    ",best[1]);
        }
        return 0;
    }
  • 相关阅读:
    vue使用elementui合并table
    使用layui框架导出table表为excel
    vue使用elementui框架,导出table表格为excel格式
    前台传数据给后台的几种方式
    uni.app图片同比例缩放
    我的博客
    【C语言】取16进制的每一位
    SharePoint Solution 是如何部署的呢 ???
    无效的数据被用来用作更新列表项 Invalid data has been used to update the list item. The field you are trying to update may be read only.
    SharePoint 判断用户在文件夹上是否有权限的方法
  • 原文地址:https://www.cnblogs.com/FrankChen831X/p/11419331.html
Copyright © 2011-2022 走看看