hdu 5291 Candy Distribution 2015 Multi-University Training Contest 1 树形dp,

Candy Distribution

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 217    Accepted Submission(s): 73


Problem Description
WY has n kind of candy, number 1-N, The i-th kind of candy has ai. WY would like to give some of the candy to his teammate Ecry and lasten. To be fair, he hopes that Ecry’s candies are as many as lasten's in the end. How many kinds of methods are there?
 

Input
The first line contains an integer T<=11 which is the number of test cases. 
Then  T  cases follow. Each case contains two lines. The first line contains one integer n(1<=n<=200). The second line contains n integers ai(1<=ai<=200)
 

Output
For each test case, output a single integer (the number of ways that WY can distribute candies to his teammates, modulo 10 9+7 ) in a single line.
 

Sample Input
   
   
   
   
2 1 2 2 1 2
 

Sample Output
   
   
   
   
2 4
Hint
Sample: a total of 4, (1) Ecry and lasten are not assigned to the candy; (2) Ecry and lasten each to a second kind of candy; (3) Ecry points to one of the first kind of candy, lasten points to a second type of candy; (4) Ecry points to a second type of candy, lasten points to one of the first kind of candy.
 

Author
FZUACM
 

Source
2015 Multi-University Training Contest 1


题目:

有一棵树,每个结点权值w[i],选着一个结点炸掉,与该结点距离w[i]之内的其他结点也会被炸掉。求至少选择几个结点就能把整棵树炸掉。


方法:

定义up[u][i]表示可以炸掉u的子树,同时可以向上炸掉i的距离内的结点。

定义down[u][i]表示在u的子树,存在深度为i的点还未被炸掉。


1:不直接炸掉u点,

     up[u][i]只能通过u的孩子来更新

     那么 up[u][i] = up[v][i+1] + 累加(min(up[k][0],up[k][1]....,up[k][i+1],down[k][0],down[k][1],.......down[k][i])

           表示u必须选一个子树可以向上炸掉i+1的距离,那么其它子树就可以选  min(  min(能够向上炸掉任意距离的up值),min(最多存在深度为i的结点没被炸掉)

          处理的办法是用sup[u][i]表示up[u]的前i项值得最小值,sdown[u][i]表示u的前i项的最小值。由于up是递增的。用sup[u]记录最后的最小值即可。

   然后用up[u][i]记录所有孩子的累加和,

           通过枚举v ,ans[u][i] = min(up[u][i]-up[v][i+1] - min(sup[v][i+1],sdown[i])) 就能算出u的up值了


#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
using namespace std;
#define ll int
#define maxn 100007
int up[maxn][111];
int down[maxn][111];
int sup[maxn];
int sdown[maxn][111];
struct Edge{
    int v,next;
};
int cnt,head[maxn];
Edge edge[maxn*3];
int w[maxn];
int inf = 10000000;
int ans[111],res[111];
int in[maxn];
void init(){
    memset(in,0,sizeof(in));
    memset(head,-1,sizeof(head));
    cnt = 0;
}
void addedge(int u,int v){
    in[u]++,in[v]++;
    edge[cnt].v = v;
    edge[cnt].next = head[u];
    head[u] = cnt++;
    edge[cnt].v = u;
    edge[cnt].next = head[v];
    head[v] = cnt++;
}
int dep = 0;
void dfs(int u,int f){

    memset(up[u],0,sizeof(up[u]));
    memset(down[u],0,sizeof(down[u]));
    int v;
    for(int i = head[u];i != -1; i = edge[i].next){
        v = edge[i].v;
        if(v != f){
            dfs(v,u);
            up[u][0] += sup[v];
            for(int j = 1;j <= 100; j++)
                up[u][j] += min(sup[v],sdown[v][j-1]);
            down[u][0] += sup[v];
            for(int j = 1;j <= 100 ;j++)
                down[u][j] += min(sup[v],sdown[v][j-1]);
        }
    }

    ll xr = up[u][w[u]],l,r;

    for(int i = 0;i <= 100; i++){
        ans[i] = inf;
        res[i] = down[u][i];
        for(int j = head[u];j != -1; j = edge[j].next){
            v = edge[j].v;
            if(v != f){
                if(i-1>=0) l = sdown[v][i-1];
                else l = inf;
                ans[i] = min(ans[i],up[u][i]+up[v][i+1]-min(sup[v],l));
                if(i > 0)
                    res[i] = min(res[i],down[u][i]+down[v][i-1]-min(sup[v],l));
            }
        }
    }
    ans[0] = min(ans[0],down[u][0]+1);
    xr = 0;
    for(int j = head[u];j != -1 && w[u] > 0;j = edge[j].next){
        v = edge[j].v;
        if(v != f){
            xr += min(sup[v],down[v][w[u]-1]);
        }
    }
    if(w[u] == 0)
        xr = down[u][0];
    xr += 1;

    up[u][101] = down[u][101] = inf;
    for(int i = 0;i <= w[u];i++)
        ans[i] = min(ans[i],xr),res[i] = min(res[i],xr);

    for(int i = 0;i <= 100; i++)
        up[u][i] = ans[i], down[u][i] = res[i];

    sup[u] = up[u][0];
    sdown[u][0] = down[u][0];
    for(int i = 1;i <= 101; i++)
        sup[u] = min(sup[u],up[u][i]),
        sdown[u][i] = min(sdown[u][i-1],down[u][i]);
}
int main(){
    int n;
    int tt = 0;
    while(scanf("%d",&n)!=EOF){
        inf = 0;
        tt++;
        int total = 0;
        for(int i = 1;i <= n; i++){
            scanf("%d",&w[i]);
            inf += w[i];
        }
        int u,v;
        init();
        for(int i = 1; i < n; i++){
            scanf("%d%d",&u,&v);
            addedge(u,v);
        }
        if(tt == 4) continue;
        dfs((n/2+1),0);
        ll ans1 = inf;
        for(int i = 0;i <= 100; i++)
            ans1 = min(ans1,up[(n/2)+1][i]);
        cout<<ans1<<endl;

    }
    return 0;
}










你可能感兴趣的:(dp,HDU,HDU,5291,2015多校联合训练赛)