poj 1155 树状dp + 背包

来源:互联网 发布:php获取上传文件 编辑:程序博客网 时间:2024/06/06 06:39

链接:http://poj.org/problem?id=1155

题意:播放电视信号,信号塔和用户构成了一棵树,有n-m个信号塔,n-m+1~n是用户= =,两个节点之间传输需要花钱,问在电视台不亏损的情况下最多多少个用户能收看。。

思路:传说中的树状dp= =,dp  好难的样子。。这道题的状态转移方程请见代码(其实是懒得写了。。)。刚开始我想错了,后来想了想发现不对。。额,dp弱,没办法=。=

dp[i][j]表示i节点有j个人收看(就是给j个人信号)时最大盈利,用当前节点的儿子节点来更新,大概就是这样了。。看不懂我写的很正常~因为我也不懂。233333

附上一个博客。。http://blog.csdn.net/woshi250hua/article/details/7644959(建图自我感觉没我的方法好(其实是我习惯我这种建图方式了))

这个题用的内存好多。。MLE了两次,然后接着百度题解去。。

#include<cstdio>#include<cstring>#include<iostream>using namespace std;const int maxn = 3010;const int inf = 0x3f3f3f3f;struct Side{int v,w,next;}side[maxn*3];int node[maxn],top;void add_side(int u,int v,int w){    side[top]=(Side){v,w,node[u]};    node[u]=top++;}int n,m;int mon[maxn];//记录每个用户准备交多少保护费int dp[maxn][maxn],vis[maxn],sum[maxn];//dp[i][j]记录第i个节点拥有j个用户时最大盈利//vis记录是否访问过。。sum记录当前节点拥有几个叶子节点(叶子节点也就是用户)void init(){    memset(node,-1,sizeof(node));    //memset(dp,0,sizeof(dp));    for(int i=0;i<maxn;i++)        for(int j=0;j<maxn;j++)            dp[i][j] = -inf;    memset(vis,0,sizeof(vis));    memset(sum,0,sizeof(sum));    top=0;}void dfs(int u){    if(vis[u])return ;    vis[u] = 1;    dp[u][0] = 0;    int tot=0;    int p = node[u];    while(p!=-1){        tot++;        dfs(side[p].v);        sum[u] += sum[side[p].v];        p = side[p].next;    }    if(tot==0){        sum[u] = 1;        dp[u][1] = mon[u];    }    else {        for(int i = node[u];i!=-1;i = side[i].next){            for(int j = sum[u];j>=1;j--){                for(int k = sum[side[i].v];k>=1;k--){                    if(j>=k&&dp[u][j-k]!=-inf&&dp[side[i].v][k]!=-inf)                        dp[u][j] = max(dp[u][j] ,dp[u][j-k] + dp[side[i].v][k] - side[i].w);                }            }        }    }}int main(){    while(~scanf("%d%d",&n,&m)){        init();        for(int i=1;i<=n-m;i++){            int all;            scanf("%d",&all);            while(all--){                int v,w;                scanf("%d%d",&v,&w);                add_side(i,v,w);            }        }        for(int i=n-m+1;i<=n;i++)            scanf("%d",&mon[i]);        dfs(1);        for(int i=n;i>=0;i--)            if(dp[1][i]>=0){printf("%d\n",i);break;}    }    return 0;}


0 0
原创粉丝点击