• POJ 1155 TELE 背包型树形DP 经典题


    由电视台,中转站,和用户的电视组成的体系刚好是一棵树

    n个节点,编号分别为1~n,1是电视台中心,2~n-m是中转站,n-m+1~n是用户,1为root

    现在节点1准备转播一场比赛,已知从一个节点传送数据到达另一个节点,电视台需要一定的费用

    若可以传送数据到达用户的节点n-m+1~n,这些用户各自愿意支付一定的费用给电视台

    现在电视台希望在不亏本的情况下为尽量多的用户转播比赛

    输出最多可以为多少用户转播比赛

    背包类型的树形DP第一题

    dp[i][j]表示以节点i为根的子树有j个用户获得转播,电视台的最大收益

    由于收益有正有负

    初始化:

    dp[i][0]=0

    dp[i][j]=-inf(j>0)

    目标:dp[1][j]>=0的条件下最大的j

    (dp[1][j]>=0表示电视台不亏本)

    dfs的过程递推dp

    有个主意的地方写在了注释

      1 #include<cstdio>
      2 #include<cstring>
      3 
      4 using namespace std;
      5 
      6 inline int max(int a,int b)
      7 {
      8     return a>b?a:b;
      9 }
     10 
     11 const int maxn=3005;
     12 const int inf=0x3f3f3f3f;
     13 
     14 int dp[maxn][maxn];
     15 int cost[maxn][maxn];
     16 int siz[maxn];
     17 struct Edge
     18 {
     19     int to,next;
     20 };
     21 Edge edge[maxn];
     22 int head[maxn];
     23 int tot;
     24 int n,m;
     25 
     26 void addedge(int u,int v)
     27 {
     28     edge[tot].to=v;
     29     edge[tot].next=head[u];
     30     head[u]=tot++;
     31 }
     32 
     33 void init()
     34 {
     35     memset(head,-1,sizeof head);
     36     tot=0;
     37     for(int i=1;i<=n;i++)
     38     {
     39         dp[i][0]=0;
     40         for(int j=1;j<=m;j++)
     41             dp[i][j]=-inf;
     42     }
     43 }
     44 
     45 void solve();
     46 void dfs(int u);
     47 
     48 int main()
     49 {
     50     while(~scanf("%d",&n))
     51     {
     52         scanf("%d",&m);
     53         init();
     54         for(int i=1;i<=n-m;i++)
     55         {
     56             int num;
     57             scanf("%d",&num);
     58             while(num--)
     59             {
     60                 int u;
     61                 scanf("%d",&u);
     62                 scanf("%d",&cost[i][u]);
     63                 addedge(i,u);
     64             }
     65         }
     66         for(int i=n-m+1;i<=n;i++)
     67         {
     68             scanf("%d",&cost[i][maxn-1]);
     69         }
     70         solve();
     71     }
     72     return 0;
     73 }
     74 
     75 void solve()
     76 {
     77     dfs(1);
     78     for(int j=siz[1];j>=0;j--)
     79     {
     80         if(dp[1][j]>=0)
     81         {
     82             printf("%d
    ",j);
     83             return ;
     84         }
     85     }
     86     /*
     87     for(int i=0;i<=siz[1];i++)
     88         printf("%d
    ",dp[1][i]);
     89     */
     90 }
     91 
     92 void dfs(int u)
     93 {
     94     siz[u]=0;
     95     for(int i=head[u];~i;i=edge[i].next)
     96     {
     97         int v=edge[i].to;
     98         if(n-m<v)
     99         {
    100             dp[v][0]=0;
    101             dp[v][1]=cost[v][maxn-1];
    102             siz[v]=1;
    103         }
    104         else
    105         {
    106             dfs(v);
    107         }
    108         siz[u]+=siz[v];
    109         
    110         //由于更新dp[u][j]的时候
    111         //dp[u][j-k]需要表示以u为根的子树,有j-k个是从前面的儿子节点取的
    112         //所以这个时候dp[u][j-k]不可以被儿子节点v更新过(保证j-k个都是从前面取的)
    113         //所以递推时j要逆推
    114         //当然,k和j循环的顺序也就不可以交换了
    115         for(int j=siz[u];j>0;j--)
    116         {
    117             for(int k=1;k<=siz[v];k++)
    118                 if(j>=k)
    119                     dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]-cost[u][v]);
    120         }
    121     }
    122 }
    View Code
  • 相关阅读:
    Milk 结构体
    Milk 结构体
    Repeating Decimals, ACM/ICPC World Finals 1990, UVa202
    Repeating Decimals, ACM/ICPC World Finals 1990, UVa202
    DNA Consensus String, ACM/ICPC Seoul 2006, UVa1368
    DNA Consensus String, ACM/ICPC Seoul 2006, UVa1368
    Crossword Answers, ACM/ICPC World Finals 1994, UVa232
    【编程技巧】 iOS 5的StoryBoard(故事板)的一些用法
    【开发技术】storyboard和nib的差别
    【编程技巧】ExtJs 设置GridPanel表格文本垂直居中
  • 原文地址:https://www.cnblogs.com/-maybe/p/4749155.html
Copyright © 2020-2023  润新知