标签:int 题解 花坛 Landscaping 泥土 数组 -- dp
其实是一道 USACO2012年3月月赛银组的
大水题·
题目描述
有$n$个花坛,编号为$1,2,.....,n$。现在每个花坛有$A_i$个泥土,要通过以下操作,将它们变为$B_i$个>泥土:
- 在某个花坛增加一个泥土 ,要花费$X$。
- 在某个花坛减少一个泥土,要花费$Y$.。
- 把某个花坛的泥土搬到另一个花坛里,要花费$Z|i-j|$。
求花费最小值?
分析
我觉得这题的$dp$的方法很妙
存储
乍一看,我们会直接把$a$数组和$b$数组的值直接存起来,像这样:
数组 | 值 | |||
---|---|---|---|---|
a | 1 | 2 | 3 | 4 |
b | 4 | 3 | 2 | 0 |
观察题目,每次操作的是泥土不是花坛,所以我们可以把每个泥土在哪个花坛存起来,像这样: | ||||
数组 | 值 | |||
-- | -- | -- | -- | -- |
a | 1 | 2 | 2 | 2 |
b | 1 | 1 | 1 | 1 |
这好像是某一道题 |
具体代码
for(int i=1,u,v;i<=n;i++)
{
cin>>u>>v;
for(int j=1;j<=u;j++)a[++ta]=i;
for(int j=1;j<=v;j++)b[++tb]=i;
}
状态
既然是$dp$那就得知道$dp_i,_j$表示的是什么?
这里我们可以用答案倒推法
最后要求$a$数组经过最少的操作变为$b$数组
输出的是$dp[ta][tb]$
就能看得出来$dp[i][j]$表示把数组的前i项变得和b数组的前j项完全一样的最小花费。
初始化
把$a$的前$i$变成$b$的前$0$,只需将$a$的泥土全部减掉,代价为$iy$
把$a$的前$0$变成$b$的前$i$,只需将$a$的泥土全部加上,代价为$ix$
具体代码
for(int i=1;i<=ta;i++)dp[i][0]=y*i;
for(int i=1;i<=tb;i++)dp[0][i]=x*i;
状态转移
$dp[i][j]$可以通过$3$种操作退出来:
1.通过$dp[i][j-1]+x$推出,对应题目第一条;
2.通过$dp[i-1][j]+y$推出,对应题目第二条;
3.通过$dp[i-1][j-1]$推出,对应题目第三条;
注意:不能从$dp[i+1][j]$之类的推出。
具体代码
dp[i][j]=min(min(dp[i-1][j]+y,dp[i][j-1]+x),dp[i-1][j-1]+z*abs(a[i]-b[j]));
代码
良好做题习惯,不要复制
#include<bits/stdc++.h>
using namespace std;
int n,x,y,z,a[1010],b[1010],ta,tb,dp[1010][1010];
int main()
{
cin>>n>>x>>y>>z;
for(int i=1,u,v;i<=n;i++)
{
cin>>u>>v;
for(int j=1;j<=u;j++)a[++ta]=i;
for(int j=1;j<=v;j++)b[++tb]=i;
}
for(int i=1;i<=ta;i++)dp[i][0]=y*i;
for(int i=1;i<=tb;i++)dp[0][i]=x*i;
for(int i=1;i<=ta;i++)
{
for(int j=1;j<=tb;j++)
{
dp[i][j]=min(min(dp[i-1][j]+y,dp[i][j-1]+x),dp[i-1][j-1]+z*abs(a[i]-b[j]));
}
}
cout<<dp[ta][tb];
}
推荐
看完这片题解可以可以做一下Landscaping P和编辑距离这两题
标签:int,题解,花坛,Landscaping,泥土,数组,--,dp 来源: https://www.cnblogs.com/gdfzlcx/p/16583387.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。