Ural 2072:Kirill the Gardener 3(DP)

http://acm.timus.ru/problem.aspx?space=1&num=2072

题意:有n朵花,每朵花有一个饥渴值。现在浇花,优先浇饥渴值小的(即从小到大浇),浇花需要耗费1个单位时间,从第i个位置走到第j个位置需要耗费abs(j-i)个单位时间,问浇完所有的花需要耗费的最少时间是多少。

思路:考虑到有饥渴值一样的花,那么只要考虑怎么在饥渴值相同的情况下取最优,那问题便可以迎刃而解了。

首先想,要让时间耗费的少,那么就尽量不要走重复的路程,所以想到这里,可以确定:对于某一个饥渴值x,一定是从饥渴值为x的最左边的位置走到饥渴值为x的最右边的位置,或者从最右边的位置走到最左边。因为这样就可以变成一条直线了,不会走多余的路程。

考虑到我们只需要知道每个饥渴值对应的最左边和最右边的位置,因此我们只要处理出Left[i],Right[i]数组即可。因为数据大,所以需要离散化。

定义两个状态:dp[i][0]为走到饥渴值为i的花的时候从最左边走到最右边耗费的最短时间,dp[i][1]为走到饥渴值为i的花的时候从最右边走到最左边耗费的最短时间。

知道这两个状态后,转移方程就不难列出:

dp[i][0] = Right[i] - Left[i] + min(dp[i-1][1] + abs(Left[i-1] - Left[i]), dp[i-1][0] + abs(Right[i-1] - Left[i]));

dp[i][1] = Right[i] - Left[i] + min(dp[i-1][1] + abs(Left[i-1] - Right[i]), dp[i-1][0] + abs(Right[i-1] - Right[i]));

注意要用longlong。可怜的队友因为这个抓狂了一个下午。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 #define N 100005
 5 #define INF 0x3f3f3f3f
 6 LL dp[N][2], a[N], b[N]; int Left[N], Right[N];
 7 // dp[i][0] Left -> Right , dp[i][1] Right -> Left
 8 
 9 int main() {
10     int n;
11     while(~scanf("%d", &n)) {
12         for(int i = 1; i <= n; i++) scanf("%lld", &a[i]), b[i] = a[i];
13         sort(b + 1, b + 1 + n);
14         int cnt = unique(b + 1, b + 1 + n) - b - 1;
15         memset(Left, INF, sizeof(Left));
16         for(int i = 1; i <= n; i++) { // 离散化
17             a[i] = lower_bound(b + 1, b + 1 + cnt, a[i]) - b;
18             Left[a[i]] = min(Left[a[i]], i);
19             Right[a[i]] = max(Right[a[i]], i);
20         }
21         dp[1][0] = Right[1] - 1; // 走到右端
22         dp[1][1] = Right[1] - Left[1] + Right[1] - 1; // 先到右端再走到左端
23         for(int i = 2; i <= cnt; i++) {
24             int dis = Right[i] - Left[i];
25             dp[i][0] = min(dp[i-1][1] + abs(Left[i-1] - Left[i]), dp[i-1][0] + abs(Right[i-1] - Left[i])) + dis;
26             dp[i][1] = min(dp[i-1][1] + abs(Left[i-1] - Right[i]), dp[i-1][0] + abs(Right[i-1] - Right[i])) + dis;
27         }
28         printf("%lld
", min(dp[cnt][0], dp[cnt][1]) + n);
29     }
30     return 0;
31 }
原文地址:https://www.cnblogs.com/fightfordream/p/6408539.html