We need water!

We need water!
(water.c/cpp/pas)
描述 Description
这个岛可以用一根数轴来表示。这根数轴上某些地方有露水。 一开始每个地方的露水都
是 同样多的。随着时间推移,露水会 不断蒸发。对于每一滴露水, 每一单位时间会使它失
去一单位的水。莫诺现在在数轴的 0 位置上。他每单位时间可以走一单位距离。当他到达某
一个露水的时候,他可以瞬间采集完该点的全部露水。动作的先后顺序是:采集 - 移动 - 露
水蒸发 - 采集 - 移动„„。如果 0 位置有露珠,可以直接取。
问莫诺最多能采集到多少露水。
完成此题你将得到 100 分作为帮助莫诺的奖励。
输入格式 Input Format
第一行两个整数 n 和 m 表示有 n 个露水,每个露水一开始含有 m 单位水。
接下来 n 行每行一个整数表示第 i 个露水的位置。
输出格式 Output Format
输出只有一行表示莫诺最多能采集到的水数。
样例输入 Sample Input
3 15
6
-3
1
样例输出 Sample Output
25
数据规模 Data Limitation
100%的数据,1<=N<=300,
1<=m<=1,000,000,-10,000<=x1,x2...xn<=10000。Xi≠Xj.

【题解】

这道题目和关路灯较为相似,但是我们还需要枚举取的露水的个数,然后在做类似关路灯的DP,f [ j ][ k ][ 0/1 ] 表示已经取了第j个~第k个露水,最后一次取露水是在j的位置 / k的位置时,所浪费掉(蒸发)的最少的水量,可以得到转移

p表示枚举的露水个数,i 表示当前取的露水个数,j 和 k 枚举取的露水是第j个~第k个,可以得到转移:

f[j][k][0] = min(f[j+1][k][0]+(a[j+1]-a[j]) * (p-i+1), f[j+1][k][1]+(a[k]-a[j])* (p-i+1));

f[j][k][1] = min(f[j][k-1][1]+(a[k]-a[k-1]) * (p-i+1), f[j][k-1][0]+(a[k]-a[j])* (p-i+1));

然后用p*m(总水量)- 最少的浪费掉的水量来更新ans。如果一开始0的位置没有露水,需要先添加一个露水,然后最后再减掉。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=400;
int n,m,a[N],f[N][N],g[N][N],ans=0;
inline int max(int a,int b) {
    return a>b?a:b;
}
int main() {
    freopen("water.in","r",stdin);
    freopen("water.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1; i<=n; i++)
        scanf("%d",&a[i]);
    a[++n]=0;
    sort(a+1,a+1+n);
    int s;
    for(int i=1; i<=n; i++)
        if(a[i]==0) {
            s=i;
            break;
        }
    /*memset(f,0x3f,sizeof(f));
    memset(g,0x3f,sizeof(g));
    f[s][s]=g[s][s]=0;
    for(int len=2; len<=n; len++) {
        for(int i=1; i+len-1<=n; i++) {
            int j=i+len-1;
            f[i][j]=min(f[i+1][j]+(a[i+1]-a[i])*(n-len+1),g[i+1][j]+(a[j]-a[i])*(n-len+1));
            g[i][j]=min(g[i][j-1]+(a[j]-a[j-1])*(n-len+1),f[i][j-1]+(a[j]-a[i])*(n-len+1));
            ans=max(ans,(len-1)*m-min(f[i][j],g[i][j]));
        }
    }*/
    for(int p=1; p<=n; p++) {
        memset(f,0x3f,sizeof(f));
        memset(g,0x3f,sizeof(g));
        f[s][s]=g[s][s]=0;
        for(int len=2; len<=p; len++)
            for(int i=1; i+len-1<=n; i++) {
                int j=i+len-1;
                f[i][j]=min(f[i+1][j]+(a[i+1]-a[i])*(p-len+1),g[i+1][j]+(a[j]-a[i])*(p-len+1));
                g[i][j]=min(g[i][j-1]+(a[j]-a[j-1])*(p-len+1),f[i][j-1]+(a[j]-a[i])*(p-len+1));
                ans=max(ans,(len-1)*m-min(f[i][j],g[i][j]));
            }
    }
    printf("%d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/kcfzyhq/p/8568474.html