动态规划:奶牛吃草问题

奶牛吃草

问题描述

在X轴上,用一个整树表示坐标。题目给定一个坐标表示奶牛起始位置,再给定一组坐标表示青草的位置,给出一个设定:每过一个单位时间,青草口感损失1个单位。
假定奶牛运行速度就是一个单位/单位时间,忽略奶牛吃草的时间,并且要求奶牛吃掉所有青草,问最小青草损失口感为多少。

输入格式

第一行两个用空格隔开的整数 n,k,分别表示青草的数目和奶牛的初始坐标。
第 2 行到第 n+1 行,第 i+1 行有一个整数 x[i],描述第 i 棵青草的坐标。

输出格式

一行一个整数,表示吃掉所有青草的前提下,最小损失的口感之和。保证答案在 32 位有符号整数的范围内。

样例输入

4 10
1
9
11
19

样例输出

44

样例解释

先跑到 9,然后跑到 11,再跑到 19,最后到 1,可以让损失的口感总和为 29+1+3+11=44。可以证明不存在比这更优的解。

代码实现
#include <bits/stdc++.h>
using namespace std;

// ================= 代码实现开始 =================

/* 请在这里设计你的算法 */
const int N = 2003;
int dp[N+2][N+2][2];

// 本函数求解答案(损失的最小口感和)
// n:青草棵数
// k:奶牛的初始坐标
// x:描述序列 x(这里需要注意的是,由于 x 的下标从 1 开始,因此 x[0] 的值为 -1,你可以忽略它的值,只需知道我们从下标 1 开始存放有效信息即可),意义同题目描述
// 返回值:损失的最小口感和
int getAnswer(int n, int k, vector<int> x) {
    /* 请在这里设计你的算法 */
	sort(x.begin()+1, x.end());
	for(int i=1; i<=n; ++i)//只吃一棵草
		dp[i][i][0] = dp[i][i][1] = abs(x[i] - k) * n;
	for(int len=1; len<n; ++len){
		for(int L=1, R; (R=L+len)<=n; ++L){                                  //[L,R]表示已被吃掉的草的连续区间
			dp[L][R][0] = min(dp[L+1][R][0] + (n-(R-L)) * abs(x[L] - x[L+1]),//原本在左,继续向左吃
			                  dp[L+1][R][1] + (n-(R-L)) * abs(x[L] - x[R])); //原本在右,跑到左来吃
			dp[L][R][1] = min(dp[L][R-1][1] + (n-(R-L)) * abs(x[R] - x[R-1]),//原本在右,继续向右吃
			                  dp[L][R-1][0] + (n-(R-L)) * abs(x[R] - x[L])); //原本在左,跑到右来吃
		}
	}
	return min(dp[1][n][0], dp[1][n][1]);
}

// ================= 代码实现结束 =================

int main() {
    int n, k, tmp;
    vector<int> x;
    scanf("%d%d", &n, &k);
    x.clear();
    x.push_back(-1);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &tmp);
        x.push_back(tmp);
    }
    int ans = getAnswer(n, k, x);
    printf("%d\n", ans);
    return 0;
}
来源

来自邓俊辉老师的《算法训练营》第一期。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值