HDU 1011 树形dp

//运行时间 2683 MS 
#include<iostream>
#include<algorithm>
#include<vector>
#include<cstdio>
#include<cstring>
using namespace std;
struct Vertex{
    int v;
    Vertex* next;
}vertex[215];
Vertex* head[102];
int men,n,men_needed[102],brains[102],a,b,dp[102][102],cnt; 
bool visited[102];
void link(int a,int b){
    vertex[++cnt].v = b; 
    if(head[a]==NULL) {
        head[a] = &vertex[cnt];
        vertex[cnt].next = NULL;
    }
    else {
        vertex[cnt].next = head[a];
        head[a] = &vertex[cnt];
    }
}

int R[102][102];

int solve(int i,int men_left){
    if(R[i][men_left]) return R[i][men_left];
    
    if(men_left<men_needed[i]||men_left==0) return 0; //注意 <span style="font-family: Arial, Helvetica, sans-serif;">men_left==0 的情况时返回0 ,</span><span style="font-family: Arial, Helvetica, sans-serif;"> 虽然有时候不需要士兵去战斗,但需要士兵去拿brains </span>

    visited[i] = true;

    int men_left0 = men_left;
    

    men_left-=men_needed[i];
    Vertex* p = head[i];
    int Max=-1;
    int dp[2][men_left+1],k=1;
    memset(dp,0,sizeof(dp));
    while(p!=NULL) {
        if(men_left<men_needed[p->v]||visited[p->v]) {  p = p->next; continue; }
        for(int men=0;men<=men_left;men++) {  //给当前 分支 总共分配 men 个士兵
            dp[k][men] = 0;
            for(int j=0;j<=men;j++){  //给当前 p->v 分配 j 个
                dp[k][men] = max( dp[k][men] , dp[!k][men-j] + solve(p->v,j) );
            }

        }
        p = p->next;
        k = !k;
    }
    visited[i] = false;
    
    R[i][men_left0] = brains[i] + dp[!k][men_left];
    return brains[i] + dp[!k][men_left];
}

int main(){
    while(scanf("%d%d",&n,&men)!=EOF&&(n!=-1||men!=-1)){
        memset(visited,0,sizeof(visited));
        memset(R,0,sizeof(R));
        cnt = -1;
        for(int i=0;i<102;i++) head[i] = NULL;
        for(int i=1;i<=n;i++){
            scanf("%d%d",&men_needed[i],&brains[i]);
            if(men_needed[i]>0)  men_needed[i]=(men_needed[i]-1)/20+1;
            
        }
        for(int i=1;i<n;i++){
            scanf("%d%d",&a,&b);
            link(a,b);
            link(b,a);
        }

        printf("%d\n",solve(1,men));

    }
}


上面的代码效率不够高。


//运行时间 93 MS
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <string>
#include <cstring>
#include <algorithm>
#include <iomanip>
using namespace std;
const int inf = 0x7FFFFFFF;
const int maxn = 111;
struct node{
    int v;
    node *next;
}tree[maxn<<1], *head[maxn];
int ptr,n,sum;
int dp[105][2005], bug[105], w[105];
bool vis[105];
void AddEdge(int a,int b){
    tree[ptr].v=a;
    tree[ptr].next=head[b];
    head[b]=&tree[ptr++];
}
int DFS(int cnt,int M){
    if(M==0) return 0;
    int m=M-bug[cnt];
    vis[cnt]=true;
    node *p=head[cnt];
    int Max=0;
    while(p!=NULL){
    if(vis[p->v]){ 
    p = p->next; continue;
    }
    for(int i=m ; i>=bug[p->v] ; --i){ 
    dp[p->v][i]=DFS(p->v,i);
    //cout<<p->v<<' '<<i<<"=="<<dp[p->v][i]<<endl;
    }
    for(int i=m;i>=bug[p->v];--i)  // i 为士兵个数
    for(int j=i;j>=bug[p->v];--j)
    dp[cnt][i]=max( dp[cnt][i] , dp[cnt][i-j]+dp[p->v][j] );
    p=p->next;
    } //cout<<cnt<<' '<<m<<"=="<<dp[cnt][m]<<endl;
    return w[cnt]+dp[cnt][m];
}
int main(){
int a=inf+1;
 int m;
 while(~scanf("%d%d",&n,&m)&&!(n==-1&&m==-1)){
 ptr=1;
 for(int i=1;i<=n;++i){
 int a; scanf("%d%d",&a, w+i);
 bug[i]=(a%20)?1:0;
 bug[i]+=a/20;
 //if(bug[i]==0) bug[i]=1;
 }
 memset(head,0,sizeof(head));
 for(int i=1;i<n;++i){
 int a,b; scanf("%d%d",&a,&b);
 AddEdge(b,a); AddEdge(a,b);
 }
 if(m<bug[1]){
 puts("0"); continue;
 }
 memset(dp,0,sizeof(dp));
 memset(vis,false,sizeof(vis));
 int ans=DFS(1,m);
 printf("%d\n",ans);
 }
 return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值