poj 1155 (树形DP)

poj 1155

题目:http://poj.org/problem?id=1155

树形DP。d [ u ][ i ]表示以u为根节点,用户数为i 的最大收益。状态转移方程:d[ u ][ i ] = max( d[ u ][ j ] + d[ v ][ i - j ] - cost  ,d[ u ][ i ]),i>j;注意边界条件。先开始直接将每个节点的 i 都循环成 1~m TLE了一次,还以为是算法问题,又看了下被人代码,才多增了了一个num数组,作为循环边界, = = 。的确,对于这道题目,这样能减少很大的复杂度,以后要注意了,还有最关键的就是,感觉自己DP没错,但TLE时,要先自己试着优化DP边界,不要看别人代码! 

代码如下:

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;


const int MAXN = 3333 ;


const int INF = 0x0fffffff ;


struct Edge
{
    int t,val;
    int next;
} edge[MAXN];


int head[MAXN],tot;


void add_edge(int a,int b,int val)
{
    edge[tot].val = val;
    edge[tot].t = b;
    edge[tot].next = head[a];
    head[a]=tot++;
}


int n,m;
int val[MAXN];
int d[MAXN][MAXN];


int num[MAXN];


void dfs(int u)
{
    for(int i=0;i<=m;i++)
        d[u][i]=-INF;
    d[u][0]=0;
    if(head[u]==-1)
    {
        d[u][1]=val[u];
        return ;
    }
    for(int e = head[u]; e != -1 ;e=edge[e].next)
    {
        int v = edge[e].t;
        int cost = edge[e].val;
        //printf("u = %d,v = %d\n",u,v);
        dfs(v);
        num[u]+=num[v];
        for(int i=num[u];i>=1;i--)
            for(int j=0;j<i;j++)
            {
                d[u][i] = max(d[u][j]+d[v][i-j]-cost,d[u][i]);
                //printf("%d,%d = %d\n",u,i,d[u][i]);
            }
    }
}


int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        memset(head,-1,sizeof(head));
        tot=0;
        for(int i=1;i<=n-m;i++)
        {
            int k;
            scanf("%d",&k);
            int a,b;
            while(k--)
            {
                scanf("%d%d",&a,&b);
                add_edge(i,a,b);


            }
            val[i]=0;
            num[i]=0;
        }
        for(int i=n-m+1;i<=n;i++)
        {
            num[i]=1;
            scanf("%d",&val[i]);
        }
        dfs(1);
        int ans=0;
        for(int i = m;i>=1;i--)
            if(d[1][i]>=0)
            {
                ans=i;
                break;
            }
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值