分组背包+树形DP(BY LPX)

来源:互联网 发布:淘宝怎么修改商品类目 编辑:程序博客网 时间:2024/05/15 19:00

专题传送门:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=24217#overview

A.POJ 1155

/*类型:树形DP题意:广播一场比赛,有发射站和用户,用户为叶子节点。每个发射站有消耗,到达用户有收益,现在问在不赔钱的情况下怎样使用户最大思路:dp[i][j] 为给第i个节点分配k个用户的收益(可以为负),显然使dp[1][j]为正的最大j为所求*/#include<stdio.h>#include<string.h>#include<stdlib.h>#include<string>#include<map>#include<queue>#include<vector>#include<algorithm>#define maxn 3100#define maxm 1100#define INF (1 << 28)#define TP int#define LL long long#define DB double#define Mid(x) ((x) >> 1)#define Lc(x) ((x) << 1)#define Rc(x) (((x) << 1)|1)#define Clear(a,b) memset(a,b,sizeof(a))using namespace std;inline TP Max(TP a,TP b){    if (a > b) return a;    return b;}inline TP Min(TP a,TP b){    if (a > b) return b;    return a;}bool cmp(TP a,TP b){    return a < b;}//BEGINstruct EDGE{    int v,w;    };bool cmp1(EDGE a,EDGE b){    return a.w > b.w;}int dp[maxn][maxn],    val[maxn],    son[maxn];vector <EDGE> links[maxn];int dfs1(int k){    int i,mm;    mm = links[k].size();    if (mm == 0) son[k] = 1;    else son[k] = 0;    for(i = 0;i < mm;i++)        son[k] += dfs1(links[k][i].v);    return son[k];}void dfs2(int k){    //printf("%dxxx\n",k);    int mm = links[k].size(),        i,ii,jj,now_limt = 0;    dp[k][0] = 0;    if (mm == 0) {        dp[k][1] = val[k];        }    for(i = 0;i < mm;i++)        dfs2(links[k][i].v);    for(i = 0;i < mm;i++) //分组背包,枚举组        for(ii = (now_limt += son[links[k][i].v]);ii >= 1;ii--)            for(jj = 1;jj <= ii && jj <= son[links[k][i].v];jj++)                dp[k][ii] = Max(dp[k][ii],dp[k][ii-jj] + dp[links[k][i].v][jj] - links[k][i].w);    //    //printf("%d:\n",k);for(i = 1;i <= son[k];i++) printf("%d ",dp[k][i]);printf("\n");    return ;}int Work(){    int n,m,tran,i,j,t;    EDGE tmp;    scanf("%d%d",&n,&m);    for(i = 0;i < maxn;i++)        for(j = 0;j < maxn;j++)            dp[i][j] = -INF;    Clear(son,0);    tran = n - m;    for(i = 1;i <= tran;i++) {        scanf("%d",&t);        for(j = 1;j <= t;j++){            scanf("%d%d",&tmp.v,&tmp.w);            links[i].push_back(tmp);            }        //sort(links[i].begin(),links[i].end(),cmp1);        }    for(;i <= n;i++)        scanf("%d",&val[i]);    dfs1(1);                    //第一遍DFS统计每个点的子树的点数    //for(i = 1;i <= n;i++)    //    printf("%d_%d\n",i,son[i]);    dfs2(1);                    //第二遍DFS开始DP   // for(i = 1;i <= m;i++)   //     printf("%d %d\n",i,dp[1][i]);    int ans = m;    while(dp[1][ans] < 0) ans--;    printf("%d\n",ans);    return 0;}int main(){    //freopen("test.in","r",stdin);    Work();    return 0;}

B.HDU 1011

/*类型:树形DP题意:一个虫子巢穴为树形结构,每个房间都有一些虫子和一定的概率存在脑虫。现在给你一定的战士,1战士可以消灭20个虫子,让你使打到脑虫的可能性最大思路:dp[i][j]代表打i子树要j战士时的最大可能*/#include<stdio.h>#include<string.h>#include<stdlib.h>#include<math.h>#include<string>#include<map>#include<queue>#include<vector>#include<algorithm>#define maxn 210#define maxm 110#define INF (1 << 28)#define TP int#define LL long long#define DB double#define Mid(x) ((x) >> 1)#define Lc(x) ((x) << 1)#define Rc(x) (((x) << 1)|1)#define Clear(a,b) memset(a,b,sizeof(a))using namespace std;inline TP Max(TP a,TP b){    if (a > b) return a;    return b;}inline TP Min(TP a,TP b){    if (a > b) return b;    return a;}bool cmp(TP a,TP b){    return a < b;}//BEGINint m;int dp[maxn][maxn],bug[maxn],sum_bug[maxn],boss[maxn];vector <int> edge[maxn];void dfs2(int k,int fa){    //printf("%d\n",k);    int mm = edge[k].size(),i,ii,jj;    for(i = 0;i < mm;i++)        if (edge[k][i] != fa)            dfs2(edge[k][i],k);    //if ((mm == 1 && fa > 0) || mm == 0)    //    if (bug[k] <= m) dp[k][bug[k]] = boss[k];    for(i = bug[k];i <= m;i++) dp[k][i] = boss[k];    for(i = 0;i < mm;i++)        if (edge[k][i] != fa){            for(ii = m;ii >= bug[k];ii--)                for(jj = 1;jj <= ii-bug[k];jj++)                    dp[k][ii] = Max(dp[k][ii],dp[k][ii-jj] + dp[edge[k][i]][jj]);            }    //printf("%d: %d\n",k,boss[k]);    //for(i = 0;i <= sum_bug[k];i++) printf("%d ",dp[k][i]);printf("\n");    return ;}int Work(){    int n,i,tmp_u,tmp_v;    scanf("%d%d",&n,&m);    if (n == -1) return 0;    for(i = 1;i <= n;i++)        edge[i].clear();    Clear(dp,0);    Clear(sum_bug,0);    Clear(bug,0);    for(i = 1;i <= n;i++)        scanf("%d%d",&bug[i],&boss[i]),bug[i] = (bug[i] + 19) / 20;    //for(i = 1;i <= n;i++)   printf("%d ",bug[i]);printf("\n");    for(i = 1;i < n;i++){        scanf("%d%d",&tmp_u,&tmp_v);        edge[tmp_u].push_back(tmp_v);        edge[tmp_v].push_back(tmp_u);        }    if (m == 0) {        printf("0\n");        return 1;        }    dfs2(1,0);    printf("%d\n",dp[1][m]);    return 1;}int main(){    //freopen("test.in","r",stdin);    while(Work());    return 0;}//END

C.POJ 1947

/*类型:树形DP题意:给出一棵树,问最少切断几条边可以得到有p个结点的子树思路:dp[i][j]代表第i个点为根的子树要得到j个节点的子树最少切多少个边*/#include<stdio.h>#include<string.h>#include<stdlib.h>#include<math.h>#include<string>#include<map>#include<queue>#include<vector>#include<algorithm>#define maxn 200#define maxm 1100#define INF (1000000)#define TP int#define LL long long#define DB double#define Mid(x) ((x) >> 1)#define Lc(x) ((x) << 1)#define Rc(x) (((x) << 1)|1)#define Clear(a,b) memset(a,b,sizeof(a))using namespace std;inline TP Max(TP a,TP b){    if (a > b) return a;    return b;}inline TP Min(TP a,TP b){    if (a > b) return b;    return a;}bool cmp(TP a,TP b){    return a < b;}//BEGINint p,ans;int dp[maxn][maxn];vector <int> edge[maxn];void dfs(int k){    int mm = edge[k].size(),        i,ii,jj;    if (k == 1) dp[k][1] = mm;    else dp[k][1]  = mm + 1;    dp[k][0] = 1;    for(i = 0;i < mm;i++) {        dfs(edge[k][i]);        for(ii = p;ii >= 1;ii--)            for(jj = 1;jj <= ii-1;jj++)                dp[k][ii] = Min(dp[k][ii],dp[k][ii-jj] + dp[edge[k][i]][jj] - 2);        }    //printf("%3d:",k);for(i = 0;i <= p;i++) printf("%9d",dp[k][i]);printf("\n");    if (dp[k][p] < ans) ans = dp[k][p];    return ;}int Work(){    int n,i,fa,son,j;    scanf("%d%d",&n,&p);    for(i = 0;i <= n;i++)        for(j = 0;j <= p;j++)            dp[i][j] = INF;    for(i = 1;i < n;i++) {        scanf("%d%d",&fa,&son);        edge[fa].push_back(son);        }    ans = INF;    dfs(1);    printf("%d\n",ans);    return 0;}int main(){    //freopen("test.in","r",stdin);    Work();    return 0;}//END

D.HDU 1561

/*类型:树形DP题意:取M个城堡,使那啥最大思路:不说了,桑心*/#include<stdio.h>#include<string.h>#include<stdlib.h>#include<math.h>#include<string>#include<map>#include<queue>#include<vector>#include<algorithm>#define maxn 250#define maxm 1100#define INF (1 << 28)#define TP int#define LL long long#define DB double#define Mid(x) ((x) >> 1)#define Lc(x) ((x) << 1)#define Rc(x) (((x) << 1)|1)#define Clear(a,b) memset(a,b,sizeof(a))using namespace std;inline TP Max(TP a,TP b){    if (a > b) return a;    return b;}inline TP Min(TP a,TP b){    if (a > b) return b;    return a;}bool cmp(TP a,TP b){    return a < b;}//BEGINint n,m;int dp[maxn][maxn],val[maxn];vector <int> son[maxn];void dfs(int k){    int mm = son[k].size(),        i,ii,jj;    dp[k][1] = val[k];    for(i = 0;i < mm;i++) {        dfs(son[k][i]);        for(ii = m;ii >= 1;ii--)            for(jj = 0;jj <= ii-1;jj++)                dp[k][ii] = Max(dp[k][ii],dp[k][ii-jj] + dp[son[k][i]][jj]);        }    //printf("%d: ",k);for(i = 0;i <= n;i++) printf("%d ",dp[k][i]);printf("\n");    return ;}int Work(){    int a,b,i;    scanf("%d%d",&n,&m);    if (n == 0) return 0;    m++;    Clear(dp,0);    Clear(val,0);    for(i = 0;i <= n;i++)        son[i].clear();    for(i=  1;i <= n;i++){        scanf("%d%d",&a,&val[i]);        son[a].push_back(i);        }    //for(i = 1;i <= n;i++) printf("%d ",val[i]);printf("\n");    dfs(0);    printf("%d\n",dp[0][m]);    return 1;}int main(){   // freopen("test.in","r",stdin);    while(Work());    return 0;}//END

E.HDU 1561

/*类型:树形DP题意:给出一棵树,投放K个机器人,问使全部点都被走过的情况下机器人走的总路程和最小。思路:dp[i][j]代表第i个点为根的子树要得到j个节点的子树最少切多少个边*/#include<stdio.h>#include<string.h>#include<stdlib.h>#include<math.h>#include<string>#include<map>#include<queue>#include<vector>#include<algorithm>#define maxn 11000#define maxm 12#define INF (1 << 28)#define TP int#define LL long long#define DB double#define Mid(x) ((x) >> 1)#define Lc(x) ((x) << 1)#define Rc(x) (((x) << 1)|1)#define Clear(a,b) memset(a,b,sizeof(a))using namespace std;inline TP Max(TP a,TP b){    if (a > b) return a;    return b;}inline TP Min(TP a,TP b){    if (a > b) return b;    return a;}bool cmp(TP a,TP b){    return a < b;}//BEGINstruct EDGE{    int ed,w;    } tmp;int n,k;int dp[maxn][maxm];vector <EDGE> edge[maxn];void dfs(int now,int fa){    int mm = edge[now].size(),        i,ii,jj,next;    for(i = 0;i < mm;i++)        if (edge[now][i].ed != fa) {            next = edge[now][i].ed;            dfs(next,now);            for(ii = k;ii >= 0;ii--) {                dp[now][ii] += dp[next][0] + edge[now][i].w * 2;                for(jj = 0;jj <= ii;jj++)                    dp[now][ii] = Min(dp[now][ii],dp[now][ii-jj] + dp[next][jj] + edge[now][i].w * jj);                }            }    return ;}int Work(){    int i,j,s,u,v,w;    if (scanf("%d%d%d",&n,&s,&k) == EOF) return 0;    for(i = 1;i <= n;i++) edge[i].clear();    Clear(dp,0);    for(i = 1;i < n;i++) {        scanf("%d%d%d",&u,&v,&w);        tmp.w = w;        tmp.ed = v;        edge[u].push_back(tmp);        tmp.ed = u;        edge[v].push_back(tmp);        }    dfs(s,0);    printf("%d\n",dp[s][k]);    return 1;}int main(){    //freopen("test.in","r",stdin);    while(Work());    return 0;}

F. POJ 2486

/*树形DP题意:一颗树上吃苹果,每个点上都有一定的苹果思路:状态dp[i][j][k]表示为第i个点走j步,k为0代表不回,k为1代表回则有三种转移,见代码。*/#include<stdio.h>#include<string.h>#include<stdlib.h>#include<string>#include<map>#include<queue>#include<vector>#include<algorithm>#include<math.h>#define maxn 110#define maxm 210#define INF (1 << 28)#define TP int#define LL long long#define DB double#define Mid(x) ((x) >> 1)#define Lc(x) ((x) << 1)#define Rc(x) (((x) << 1)|1)#define Clear(a,b) memset(a,b,sizeof(a))using namespace std;inline TP Max(TP a,TP b){    if (a > b) return a;    return b;}inline TP Min(TP a,TP b){    if (a > b) return b;    return a;}bool cmp(TP a,TP b){    return a < b;}//BEGINint k,n;int apple[maxn],    dp[maxn][maxm][2];vector<int>edge[maxn];void dfs(int x,int fa){    int mm,i,j,jj,son;    //0-不回 1-回    mm = edge[x].size();    for(i = 0;i < mm;i++)        if (edge[x][i] != fa)            dfs(edge[x][i],x);    for (j = 0;j <= k;j++)        dp[x][j][1] = dp[x][j][0] = apple[x];    for(i = 0;i < mm;i++)        if ((son = edge[x][i]) != fa)            for(j = k;j >= 0;j--) //又他妈傻逼了!!!!!!                for(jj = 0;jj <= j;jj++) {                    if (jj >= 2) dp[x][j][0] = Max(dp[x][j][0],dp[x][j-jj][0]+dp[son][jj-2][1]);                    if (jj >= 1) dp[x][j][0] = Max(dp[x][j][0],dp[x][j-jj][1]+dp[son][jj-1][0]);                    if (jj >= 2) dp[x][j][1] = Max(dp[x][j][1],dp[x][j-jj][1]+dp[son][jj-2][1]);                    }    return ;}int Work(){    int i,u,v;    if (scanf("%d%d",&n,&k) == EOF) return 0;    Clear(dp,0);    Clear(apple,0);    for(i = 1;i <= n;i++) scanf("%d",&apple[i]);    for(i = 1;i <= n;i++) edge[i].clear();    for(i = 1;i < n;i++) {        scanf("%d%d",&u,&v);        edge[u].push_back(v);        edge[v].push_back(u);        }    dfs(1,0);    printf("%d\n",dp[1][k][0]);}int main(){    //freopen("test.in","r",stdin);    while(Work());    return 0;}//END

J.HDU 4276

/*树形DP题意:思路:*/#include<stdio.h>#include<string.h>#include<stdlib.h>#include<string>#include<map>#include<queue>#include<vector>#include<algorithm>#include<math.h>#define maxn 110#define maxm 510#define OO (1 << 28)#define TP int#define LL long long#define DB double#define Mid(x) ((x) >> 1)#define Lc(x) ((x) << 1)#define Rc(x) (((x) << 1)|1)#define Clear(a,b) memset(a,b,sizeof(a))using namespace std;inline TP Max(TP a,TP b){    if (a > b) return a;    return b;}inline TP Min(TP a,TP b){    if (a > b) return b;    return a;}bool cmp(TP a,TP b){    return a < b;}//BEGINstruct EDGE{    int ed,cost;    } tmp;vector<EDGE>edge[maxn];int n,t;int dp[maxn][maxm],gold[maxn];int dfs_find(int now,int fa){    int mm,i,time;    if (now == n) return 0;    mm = edge[now].size();    for(i = 0;i < mm;i++)        if (edge[now][i].ed != fa) {            time = dfs_find(edge[now][i].ed,now) + edge[now][i].cost;            if (time >= 0) {                    edge[now][i].cost = 0;                    return time;                    }            }    return -OO;}void dfs(int now,int fa){    int mm,i,son,cost,j,jj;    mm = edge[now].size();    for(j = 0;j <= t;j++) dp[now][j] = gold[now];    for(i = 0;i < mm;i++)        if (edge[now][i].ed != fa) {            son = edge[now][i].ed;            dfs(son,now);            cost = edge[now][i].cost;            for(j = t;j >= 0;j--)                for(jj = cost*2;jj <= j;jj++)                    dp[now][j] = Max(dp[now][j] , dp[now][j-jj] + dp[son][jj-cost*2]);            }    return ;}int Work(){    int i,u,v,w;    if (scanf("%d%d",&n,&t) == EOF) return 0;    Clear(dp,0);    Clear(gold,0);    for(i = 1;i <= n;i++)        edge[i].clear();    for(i = 1;i < n;i++) {        scanf("%d%d%d",&u,&v,&w);        tmp.cost = w;        tmp.ed = u;        edge[v].push_back(tmp);        tmp.ed = v;        edge[u].push_back(tmp);        }    for(i = 1;i <= n;i++)        scanf("%d",&gold[i]);    t -= dfs_find(1,0);    //printf("%dXXX\n",t);    if (t <= 0) {        printf("Human beings die in pursuit of wealth, and birds die in pursuit of food!\n");        return 1;        }    dfs(1,0);    printf("%d\n",dp[1][t]);    return 1;}int main(){    //freopen("test.in","r",stdin);    while(Work());    return 0;}//END


原创粉丝点击