>Description
花园是由N块花圃组成的。第i块花圃初始的时候有Ai数量的泥土,要使得第i块花圃的泥土数量Ai变成Bi。
约翰有三个选择:第一,他可以买一个单位的泥土放进任意花圃中,代价是X;第二,他可以将一个单位的泥土从某一个花圃中除去,代价是Y;第三,他可以将第i块花圃中的一个单位的泥土搬运到第j块花圃中,代价是Z*|i-j|。
请帮助约翰计算为了达到目的最小需要花费的代价。
>Input
第一行四个整数,分别是N,X,Y,Z。
接下来N行,每行两个整数,分别表示Ai和Bi。
>Output
只有一行一个整数,表示最小的代价。
>Sample Input
4 100 200 1
1 4
2 3
3 2
4 0
>Sample Output
210
数据范围:1<=N<=100,0<=Ai,Bi<=10,0<=X,Y,Z<=1000。
>解题思路
我们要把花园的泥土都按照泥土计算单位分开来存储,例如,输入样例的数字存储为:122333444和111122233,一个1表示第一块花圃有1块泥土,两个2表示第二块花圃有2块泥土。
使用DP:
f[i][j]表示把前i个单位的泥土变为前j个单位的泥土的最小代价。
根据题意,有3种变法:
1购买:f[i][j-1]+x,表示前j-1块泥土都处理好了,再买一块泥土补充到第j块。
2除去:f[i-1][j]+y,表示用前i-1块泥土变为前j块泥土,多出的第i块泥土除掉。
3搬运:f[i-1][j-1]+z*|a[i]-b[j]|,表示前i-1块泥土变为前j-1块泥土,把第i块泥土搬运到第j块。
>代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,x,y,z,a[1005],b[1005],aa,bb,ta,tb,f[1005][1005];
int main()
{
memset(f,0x7f,sizeof(f)); //赋值
scanf("%d%d%d%d",&n,&x,&y,&z);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&aa,&bb);
for(int j=1;j<=aa;j++)
a[++ta]=i;
for(int j=1;j<=bb;j++)
b[++tb]=i; //存储方式
}
f[0][0]=0;
for(int i=0;i<=ta;i++)
f[i][0]=i*y;
for(int i=0;i<=tb;i++)
f[0][i]=i*x; //预处理
for(int i=1;i<=ta;i++)
for(int j=1;j<=tb;j++)
f[i][j]=min(f[i-1][j-1]+z*max(a[i]-b[j],b[j]-a[i]),min(f[i-1][j]+y,f[i][j-1]+x)); //状态转移方程
printf("%d",f[ta][tb]);
return 0;
}