您的位置:首页 > 其它

POJ 1155 TELE [树状DP]

2013-08-27 16:59 281 查看
题意:略。

思路:用dp[i][k]来表示结点i给k个用户提供节目时的最大盈利(可能为负)。

则递推方程为: dp[i][j] = max(dp[i][j], dp[i][m] + dp[v][j-m] - cost)

其中v为i的孩子,cost为i向v提供节目的花费。

另外注意代码里dp过程的这几行

for (int j = num[x]; j >= 0; j--)
for (int k = 1; k <= num[v]; k++)
dp[x][j+k] = max(dp[x][j+k], dp[x][j] + dp[v][k] - edge[i].w);


假设当前正考虑的孩子结点是v,则孩子1...(v-1)覆盖的用户数量为num[x],即i已经考虑过的用户数量。在这里枚举时需要从大到小枚举,不然可能j=1的情况会影响到j=2的情况。另一种处理方法就是,将结点i所有的dp[i][j]值每次都先用tem[j]另存起来,dp时直接用tem[j],这样就不需要考虑枚举的顺序了。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define maxn 3005
#define inf 0x3f3f3f3f
using namespace std;
struct node
{
int v, w, next;
}edge[maxn];
int num_edge, head[maxn];
void init_edge()
{
num_edge = 0;
memset(head, -1, sizeof(head));
}
void addedge(int a,int b,int c)
{
edge[num_edge].v = b;
edge[num_edge].w = c;
edge[num_edge].next = head[a];
head[a] = num_edge++;
}

int n, m, num[maxn], dp[maxn][maxn];
void dfs(int x)
{
for (int i = head[x]; i != -1; i = edge[i].next)
{
int v = edge[i].v;
dfs(v);
for (int j = num[x]; j >= 0; j--)
for (int k = 1; k <= num[v]; k++)
dp[x][j+k] = max(dp[x][j+k], dp[x][j] + dp[v][k] - edge[i].w);
num[x] += num[v];//x结点已经考虑过的用户数
}
}
int main()
{
//freopen("data.in", "r", stdin);
scanf("%d%d", &n, &m);
init_edge();
for (int i = 1; i <= n - m; i++)
{
num[i] = 0;//i已经考虑过的用户数量为0
int k;
scanf("%d", &k);
while (k--)
{
int b, c;
scanf("%d%d", &b, &c);
addedge(i, b, c);
}
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
dp[i][j] = -inf;
for (int i = n - m + 1; i <= n; i++)
{
num[i] = 1;
scanf("%d", &dp[i][1]);
}
dfs(1);
for (int i = m; i >= 0; i--) if (dp[1][i] >= 0)
{
printf("%d\n", i);
break;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: