bzoj1017(JSOI2008)魔兽地图
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1017
钱数很少,所以它也能压进状态里。
还有向上贡献几个物品。所以状态就是第 i 号物品,向上贡献 j 个,总共花 k 元的当前就能得到的力量。
然后可以树形dp。
不同的是平常的树形dp,该点的值就顺便充当前 r 个子树的值;遍历完子树就完成自己的值。
但这里的状态里有一个“向上贡献 j 个”,不太好弄。所以另开一个 g ,只关注花了多少钱和带来多少力量。
为了能用这个g转移到dp,不出现花了某些钱其实买不够向上贡献的 j 个当前物品的情况,应该把“总共买 l 个当前物品”放在最外面枚举。
并且是倒序,为了沿用上一轮的g值。
**不知为何,自己的代码比别人慢了好多!!我觉得没什么不同呀……以后再来看看吧。
#include<iostream> #include<cstdio> #include<cstring> #define ll long long using namespace std; const int N=55,M=2005;const ll INF=0x7fffffff; int n,m,head[N],xnt,du[N]; ll a[N],L[N],c[N],dp[N][N<<1][M],g[N][M],h[N][M],ans;//dp[][N<<1][]不能dp[][N][] struct Edge{ int next,to;ll w; Edge(int n=0,int t=0,ll w=0):next(n),to(t),w(w) {} }edge[N]; void dfs(int cr) { if(!head[cr]) { L[cr]=min(L[cr],m/c[cr]); for(int i=0;i<=L[cr];i++) for(int j=0;j<=i;j++) dp[cr][j][i*c[cr]]=(i-j)*a[cr]; return; } L[cr]=INF; for(int i=head[cr],v;i;i=edge[i].next) { dfs(v=edge[i].to);L[cr]=min(L[cr],L[v]/edge[i].w); c[cr]+=c[v]*edge[i].w; //只是用来限制L[cr] } L[cr]=min(L[cr],m/c[cr]); memset(g,-2,sizeof g);//g只和子树阶段、钱有关,因为dp涉及"向上贡献几个",所以不方便同时表示前几个子树的力量值 g[0][0]=0; for(int l=L[cr];l>=0;l--)//g不重赋值,所代表的状态应该足以合成当前的l个当前装备;所以需倒序 { int tot=0; for(int i=head[cr];i;i=edge[i].next) { tot++; for(int k=0;k<=m;k++)//用了k钱 for(int j=0;j<=k;j++)//j钱给v g[tot][k]=max(g[tot][k],g[tot-1][k-j]+dp[edge[i].to][l*edge[i].w][j]);//k-j钱给之前的子树 } for(int j=0;j<=l;j++) for(int k=0;k<=m;k++) dp[cr][j][k]=max(dp[cr][j][k],g[tot][k]+a[cr]*(l-j));//子树们的节余+自己的节余 } } int main() { scanf("%d%d",&n,&m);char ch;int u,x;ll z; memset(L,1,sizeof L); memset(dp,-2,sizeof dp);////// for(int i=1;i<=n;i++) { scanf("%lld %c",&a[i],&ch); if(ch=='B') { scanf("%lld%lld",&c[i],&L[i]); } else { scanf("%d",&u); for(int j=1;j<=u;j++) { scanf("%d%lld",&x,&z); edge[++xnt]=Edge(head[i],x,z);head[i]=xnt;du[x]++; } } } int tot=0; for(int i=1;i<=n;i++) if(!du[i]) { dfs(i);tot++; for(int k=0;k<=m;k++)//总共 for(int j=0;j<=m;j++)//给之前的树 h[tot][k]=max(h[tot][k],h[tot-1][j]+dp[i][0][k-j]); } for(int i=0;i<=m;i++)ans=max(ans,h[tot][i]); printf("%lld",ans); return 0; }