http://acm.hdu.edu.cn/showproblem.php?pid=1561
题目大意就不说了,都中文题...... 该题看起来计较复杂,上课的时候想了想,对于每个节点而言攻击T次,那么分配给孩子节点的次数的组合数是庞大的。然而这道题就是很暴力,DFS下面三重for循环。for循环里面就是背包过程了。吴涛的建议使得程序更加的好,对于每一个递归能够攻击的次数减1,这样能够减少许多不必要的if判断。
代码如下:
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define MAXN 205
using namespace std;
struct Node
{
int place, next;
}edge[MAXN*3];
int head[MAXN], tol, val[MAXN];
int dp[MAXN][MAXN], M, N;
inline void modify(int s1, int s2)
{
edge[tol].place = s2;
edge[tol].next = head[s1];
head[s1] = tol++;
}
bool getint( int &t )
{
char c; int f = 1;
while( c = getchar(), c != '-' && ( c < '0' || c > '9' ) )
{
if( c == EOF )
return false;
}
if( c == '-' )
f = -1;
else
t = c - '0';
while( c = getchar(), c >= '0' && c <= '9' )
t = t * 10 + c -'0';
t *= f;
return true;
}
void dfs(int f, int m)
{
int place, v;
dp[f][1] = val[f]; // 攻击一次能够得到的财富值
for (int i = head[f]; i != -1; i = edge[i].next)
{
place = edge[i].place;
if (m > 1)
dfs(place, m-1);
for (int j = m; j >= 1; --j) // 让给孩子节点攻击的次数
{
v = j+1;
for (int k = 1; k <= j; ++k) // 孩子节点贡献的攻击次数
{
if (dp[f][v] < dp[f][v-k]+dp[place][k])
{
dp[f][v] = dp[f][v-k] + dp[place][k];
}
}
} // 典型的背包过程
}
}
int main()
{
int s, v;
while (scanf("%d %d", &N, &M), M | N)
{
tol = 0;
val[0] = 0;
memset(head, -1, sizeof(head));
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= N; ++i)
{
getint(s), getint(v);
val[i] = v;
modify(s, i);
}
dfs(0, M+1);
printf("%d\n", dp[0][M+1]);
}
}