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;
}