POJ2152 树形DP

来源:互联网 发布:微信网络出错轻击屏幕 编辑:程序博客网 时间:2024/05/20 06:08

题意:这一题是陈启锋的论文中的一道题 题意是在一棵树上选取节点建立消防站 每个节点有一个代价 然后每个节点之间又有距离 距离大于每个节点承受上限的化就不能被看管 然后问题的看管所有节点最小代价是多少

解法:正确的姿势就是利用dfs进行dp 枚举每一个节点被看管的节点 然后得到的dp方式是当前节点被i节点看管的最少花费取决于每一颗 子树分别被全部看管的最佳花费或者是儿子节点也同样被i看管带来的花费

#include<cstdio>#include<vector>#include<limits.h>using namespace std;#define maxn 1111#define INF 2147483647#define min(a,b) (a)<(b)?(a):(b)#define max(a,b) (a)>(b)?(a):(b)struct edge{int v,w;}s;vector<edge>e[maxn];int n,cur,best[maxn],dp[maxn][maxn],dist[maxn][maxn],limit[maxn],cost[maxn];void init(){    for(int i=0;i<=n;++i)e[i].clear(),best[i]=INT_MAX;    for(int i=1;i<=n;++i)        for(int j=1;j<=n;++j)            dp[i][j]=INT_MAX;}void Dis(int u,int f,int dis){    dist[cur][u]=dis;    for(int i=0;i<e[u].size();++i){        int v=e[u][i].v;        int len=e[u][i].w;        if(v==f)continue;        Dis(v,u,dis+len);    }}void solve(int u,int f){    for(int i=0;i<e[u].size();++i){        if(e[u][i].v!=f)solve(e[u][i].v,u);    }    for(int i=1;i<=n;++i)        if(dist[u][i]<=limit[u]){            dp[u][i]=cost[i];            for(int j=0;j<e[u].size();++j){                int v=e[u][j].v;                if(v==f)continue;                dp[u][i]+=min(dp[v][i]-cost[i],best[v]);            }            best[u]=min(best[u],dp[u][i]);        }}int _,a,b,c;int main(){    scanf("%d",&_);    while(_--){        scanf("%d",&n);        init();        for(int i=1;i<=n;++i)scanf("%d",&cost[i]);        for(int i=1;i<=n;++i)scanf("%d",&limit[i]);        for(int i=1;i<n;++i){            scanf("%d%d%d",&a,&b,&c);            s.v=b,s.w=c;            e[a].push_back(s);            s.v=a,s.w=c;            e[b].push_back(s);        }        for(int i=1;i<=n;++i)            cur=i,Dis(i,0,0);        solve(1,0);        printf("%d\n",best[1]);            }    return 0;}


1 0
原创粉丝点击