poj 1155(ツリーDP)

2269 ワード

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配列を1つ増やし,ループ境界,==とした.确かに、この问题に対して、このようにとても大きい复雑さを减らすことができて、后で注意して、更に最も肝心なのは、自分の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
",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
",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
",ans); } return 0; }