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の境界を最适化してみて、他の人のコードを见ないでください!
コードは次のとおりです.
タイトル: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;
}