NOIP模拟题——Landscaping

2. Landscaping
题目描述
N(1 <= N <= 100)个数排成一行,值分别为A_i,现在希望把每个数对应地改成B_i。(A_i,B_i的值均在0..10之间)。改变的方式有3种:
(1)把A_i增加到B_i,每增加1,花费$X
(2)把A_i减少到B_i,每减少1,花费$Y
(3)把第i个数的值转移到第j个数,每转移1,花费为$Z*|i-j|
问:最小的花费是多少。
输入
第1行:4个整数 N, X, Y, Z (0 <= X, Y, Z <= 1000).
第2..1+N行: 每行2个整数 A_i 和 B_i.
输出
第1行:1个整数,表示最小的花费。
样例输入
4 100 200 1
1 4
2 3
3 2
4 0
样例输出
210
提示
INPUT DETAILS: There are 4 flowerbeds in a row, initially with 1, 2, 3, and 4 units of dirt. Farmer John wishes to transform them so they have 4, 3, 2, and 0 units of dirt, respectively. The costs for adding, removing, and transporting dirt are 100, 200, and 1.
OUTPUT DETAILS: One unit of dirt must be removed (from flowerbed #4), at a cost of 200. The remaining dirt can be moved at a cost of 10 (3 units from flowerbed #4 to flowerbed #1, 1 unit from flowerbed #3 to flowerbed #2).
***********************************************************************

 

 

由于加或减不一定要加完,可以将每个数拆分成几个代表单位1的数(保存编号)。

考虑DP。F[I][J]表示A数组的I状态和B数组的J状态要相等的话,最小的花费。

由于拆成单位1,所以状态转移方程:

f[i][j]=min(f[i][j],f[i-1][j]+Y);//增加X
f[i][j]=min(f[i][j],f[i][j-1]+X);//增加y等价于降低x
f[i][j]=min(f[i][j],f[i-1][j-1]+abs(a[i]-b[j])*Z);

初值:当I状态为0时,要变成j状态只能都加X;当J状态为0时,要变成I状态只能都加X(即A数组减Y)

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cmath>
 5 using namespace std;
 6 const int maxn=1005;
 7 int a[maxn],b[maxn];
 8 int temp1,temp2;
 9 int f[maxn][maxn];
10 int n,X,Y,Z;
11 inline int abs(int x)
12 {
13     if(x<0)return -x;
14     return x;
15 }
16 int main()
17 {
18     freopen("landscaping.in","r",stdin);
19     freopen("landscaping.out","w",stdout);
20     scanf("%d%d%d%d",&n,&X,&Y,&Z);
21     for(int i=1;i<=n;i++)
22     {
23         int x,y;
24         scanf("%d",&x);
25         while(x)
26         {
27             a[++temp1]=i;
28             x--;
29         }
30         scanf("%d",&y);
31         while(y)
32         {
33             b[++temp2]=i;
34             y--;
35         }
36     }
37     for(int i=1;i<=temp1;i++)//增加y等价于降低x 
38     f[i][0]=Y*i;
39     for(int j=1;j<=temp2;j++)
40     f[0][j]=X*j;//增加x
41     for(int i=1;i<=temp1;i++)
42     for(int j=1;j<=temp2;j++)
43     {
44         f[i][j]=1e8;
45         f[i][j]=min(f[i][j],f[i-1][j]+Y);//增加X
46         f[i][j]=min(f[i][j],f[i][j-1]+X);//增加y等价于降低x
47         f[i][j]=min(f[i][j],f[i-1][j-1]+abs(a[i]-b[j])*Z);
48     }
49     printf("%d",f[temp1][temp2]);
50     return 0; 
51 }

 

posted @ 2016-11-11 16:28  deadshotz  阅读(209)  评论(0编辑  收藏  举报