题解 P1860 【新魔法药水】
这题有点难想啊,看了一个小时才有思路,也许是我太弱了
首先,这道题肯定是DP。
其次,分析样例,会发现题目有个隐藏条件:只能用开局的V元钱买入药品。
经过对题面的研究,我们可以发现,那一长串药物合成关系实在不好在DP中用上,我们应当把他们变得易于处理,如用ans[i][j]表示第i个物品在用j次魔法的前提下所需最小代价(即原材料价钱)。
但ans[i][j]不太好直接求,我们可以再开一个DP数组ant[i][j]表示前i个药品在使用j次魔法前提下合成所需最小代价。这样就能通过ant[i][j]将合成原材料和合成品联系起来,顾及到 需要魔法总次数 等诸多因素。
有了以上作为基础,DP处理出结果就方便多了。设DP[i][j]为使用第i次魔法,使用j块钱所获最大利润,依此列式即可。
还有,一种药品可能有多种合成方式。我因把药品与合成关系一一对应WA了一版。
#include<bits/stdc++.h>
#define ll long long
#define re register
#define il inline
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int N=300;
int m,n,q,k,s[N],h[N],op,ans[N][N],dp[N][1005],ant[N][50];
struct line
{
int a,l,p[N];
}e[N];
il int gi()
{
re int x=0,t=1;
re char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if(ch=='-') t=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*t;
}
int main()
{
n=gi();m=gi();q=gi();k=gi();
fp(i,1,n) s[i]=gi(),h[i]=gi();
fp(i,1,m)
{
e[i].a=gi();e[i].l=gi();
fp(j,1,e[i].l) e[i].p[j]=gi();
}
fp(i,1,n) fp(j,0,k) ans[i][j]=s[i];
fp(o,1,k)
fp(i,1,m)
{
fp(j,1,e[i].l)//枚举一合成关系中的物品
{
fp(t,0,o-1)//总魔法次数
{
ant[j][t]=1e9;
fp(tt,0,t)//当前物品使用魔法次数
ant[j][t]=min(ant[j][t],ant[j-1][t-tt]+ans[e[i].p[j]][tt]);
}
}
ans[e[i].a][o]=min(ans[e[i].a][o],ant[e[i].l][o-1]);
}//处理药品合成信息
fp(i,1,n)
fp(j,0,k)
fp(t,0,k-j)//枚举当前物品使用魔法次数
fp(s,0,q-ans[i][j])//枚举使用钱数
dp[j+t][s+ans[i][j]]=max(dp[j+t][s+ans[i][j]],dp[t][s]+h[i]-ans[i][j]);//简单DP求解
printf("%d\n",dp[k][q]);
return 0;
}