 /**//*
題意:有依賴的背包,要用樹dp
《淺談幾類背包題》里提到的《金明的預算方案》類似

代碼參照這里寫的:http://hi.baidu.com/darkgtbd/blog/item/4bca2b16d955624420a4e9dc.html

1<=N<=100000, 1<=G<=10000 數據很恐怖
題目有個地方要注意到:
3. The alpc who has underling is an officer (Every officer’ number is no more than 500, like alpc21, alpc32).
也就是說非葉子節點最多有500個 所以只需開dp[500][G]即可

按照論文的方法,泛化背包合并,從O(NC^2) 用類似01背包的方法降到 O(NC)
u對兒子v dfs之前,先對dp[v][j]初始為dp[u,j]+val[v] 即強制放進去v 然后修改對v的上限
最后合并,即更新

*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<cmath>
#include<cstdlib>
#include<iostream>

using namespace std;

const int INF = 1000000000;
const int MAXN = 100010;

struct Edge
  {
int v;
Edge *next;
};

Edge *E[MAXN] , edges[MAXN*2] , *pE;

bool leaf[MAXN];
int weight[MAXN] , val[MAXN];
int dp[505][10005];


inline void add(int u,int v)
  {
pE->v = v;
pE->next = E[u];
E[u] = pE++;
}

void dfs(int u, int C)
  {
for(Edge *it = E[u] ; it ; it = it->next)
 {
int v = it->v;
if(!leaf[v])
 {
for(int j = 0 ; j <= C-weight[v]; j++)//強制放進去v
dp[v][j] = dp[u][j] + val[v];
dfs(v,C-weight[v]);//修改上限
for(int j = weight[v] ; j <= C ; j++)//兩者合并 對于dp[v,j]只有j<=C-weight[v]時才是正確的結果
if(dp[u][j] < dp[v][j-weight[v]])
dp[u][j] = dp[v][j-weight[v]];
}
else
 {
for(int j = C ; j >= weight[v] ; j--)
if(dp[u][j] < dp[u][j-weight[v]] + val[v])
dp[u][j] = dp[u][j-weight[v]] + val[v];
}
}
}

int main()
  {

#ifdef ONLINE_JUDGE
#else
freopen("in", "r", stdin);
#endif

int n ,g , f ;
while( ~scanf("%d%d",&n,&g) )
 {
pE = edges;
for(int i = 0 ; i <= n ; i++)
 {
E[i] = NULL;
leaf[i] = true;
}
weight[0] = val[0] = 0;

for(int i = 1; i <= n ;i++)
 {
scanf("%d%d%d", &weight[i] , &val[i] , &f );
if(f == i)f = 0;
leaf[f] = false;
add(f,i);
}

for(int i = 0 ;i <= g ; i++)
dp[0][i] = 0;
dfs(0,g);

int ans = 0;
for(int j = 0 ; j <= g; j++)
if(ans < dp[0][j])
ans = dp[0][j];
printf("%d\n",ans);
}
return 0;
}



|
|
常用鏈接
隨筆分類
Links
搜索
最新評論

|
|
{
int v;
for(int i=head[u];i!=-1;i=G[i].next)
{
v=G[i].e;
for(int j=0;j<=c-weight[v];j++)//強制放進去v
F[v][j]=F[u][j]+val[v];
DFS(v,c-weight[v]);//修改上限
for(int j=c;j>=weight[v];j--)
maxv(F[u][j],F[v][j-weight[v]]);//兩者合并 對于dp[v,j]只有j<=C-weight[v]時才是正確的結果
}
}
求幫助,我這樣為什么access violation,其他部分確保正確!
DFS(v,c-weight[v]);//修改上限
這里v可能很大,但是它是葉子
題目說了非葉子的編號直到500
但葉子可以到很大,自然數組越界了
所以判斷下是否是葉子,葉子的話,就不用dfs了
謝謝大牛。
用這個模版不能對付HDU 1011嗎?我加了判斷是否訪問過的vis數組也不行,已知WRONG ANSWER.
void DFS(int u,int c)//u表示節點號,c表示剩余容量
{
int v;
for(int i=head[u];i!=-1;i=G[i].next)
{
v=G[i].e;
if(vis[v]) continue;
for(int j=0;j<=c-weight[v];j++)//強制放進去v
F[v][j]=F[u][j]+val[v];
DFS(v,c-weight[v]);//修改上限
for(int j=c;j>=weight[v];j--)
maxv(F[u][j],F[v][j-weight[v]]);//兩者合并 對于dp[v,j]只有j<=C-weight[v]時才是正確的結果
}
}
@_Yuan
用這個模版不能對付HDU 1011嗎?我加了判斷是否訪問過的vis數組也不行,一直WRONG ANSWER.上面那個回復請大牛直接忽視。
void DFS(int u,int c)//u表示節點號,c表示剩余容量
{
int v;vis[u]=1;
for(int i=head[u];i!=-1;i=G[i].next)
{
v=G[i].e;
if(vis[v]) continue;
for(int j=0;j<=c-weight[v];j++)//強制放進去v
F[v][j]=F[u][j]+val[v];
DFS(v,c-weight[v]);//修改上限
for(int j=c;j>=weight[v];j--)
maxv(F[u][j],F[v][j-weight[v]]);//兩者合并 對于dp[v,j]只有j<=C-weight[v]時才是正確的結果
}
}
您試試這個數據,答案是2
2 1
0 1
0 1
1 2