USACO The Cow Run
Description
Problem 1: The Cow Run [Chris Tzamos, 2006]
Farmer John has forgotten to repair a hole in the fence on his farm, and
his N cows (1 <= N <= 1,000) have escaped and gone on a rampage! Each
minute a cow is outside the fence, she causes one dollar worth of damage.
FJ must visit each cow to install a halter that will calm the cow and stop
the damage.
Fortunately, the cows are positioned at distinct locations along a straight
line on a road outside the farm. FJ knows the location P_i of each cow i
(-500,000 <= P_i <= 500,000, P_i != 0) relative to the gate (position 0)
where FJ starts.
FJ moves at one unit of distance per minute and can install a halter
instantly. Please determine the order that FJ should visit the cows so he
can minimize the total cost of the damage; you should compute the minimum
total damage cost in this case.
Input
* Line 1: The number of cows, N.
* Lines 2..N+1: Line i+1 contains the integer P_i.
Output
* Line 1: The minimum total cost of the damage.
Sample Input
4 -2 -12 3 7
Sample Output
50
HINT
INPUT DETAILS:
Four cows placed in positions: -2, -12, 3, and 7.
OUTPUT DETAILS:
The optimal visit order is -2, 3, 7, -12. FJ arrives at position -2 in 2
minutes for a total of 2 dollars in damage for that cow.
He then travels to position 3 (distance: 5) where the cumulative damage is
2 + 5 = 7 dollars for that cow.
He spends 4 more minutes to get to 7 at a cost of 7 + 4 = 11 dollars for
that cow.
Finally, he spends 19 minutes to go to -12 with a cost of 11 + 19 = 30 dollars.
The total damage is 2 + 7 + 11 + 30 = 50 dollars.
题解:
一道区间DP的还很好的题目。
拿到题之后首先就会发现这个正负比较难搞。
但是仔细思考一下我们就可以发现,答案其实只与两点之间的距离有关,与正负并无关。并且,我们可以发现,套牛的顺序一定是按单调的,也就是说,路过的牛必须都套上,否则的话那你岂不是沙茶。
所以这个区间应该是连续的,考虑使用排序+区间DP解决。
至于正负,加一维状态表示其在零点左侧还是零点右侧。零点可以另开一个点存。
具体见代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 1002
int n;
int dp[maxn][maxn][2];
int pos[maxn];
int main()
{
scanf("%d",&n);
memset(dp,0x3f,sizeof(dp));
for(int i=1;i<=n;i++)
scanf("%d",&pos[i]);
sort(pos+1,pos+1+n);
int c=lower_bound(pos+1,pos+1+n,0)-pos;
for(int i=n;i>=c;i--)
pos[i+1]=pos[i];
pos[c]=0;
dp[c][c][1]=0;
dp[c][c][0]=0;
for(int len=2;len<=n+1;len++)
for(int i=1;i+len-1<=n+1;i++)
{
int j=i+len-1;
dp[i][j][0]=min(dp[i+1][j][0]+(pos[i+1]-pos[i])*(n-j+i+1),dp[i+1][j][1]+(pos[j]-pos[i])*(n-j+i+1));
dp[i][j][1]=min(dp[i][j-1][1]+(pos[j]-pos[j-1])*(n-j+i+1),dp[i][j-1][0]+(pos[j]-pos[i])*(n-j+i+1));
}
printf("%d",min(dp[1][n+1][0],dp[1][n+1][1]));
return 0;
}