题目描述
Problem cowrun: The Cow Run [Chris Tzamos, 2006]
The N (1 <= N <= 1,000) cows have escaped from the farm and have
gone on a rampage. Each minute a cow is outside the fence, she
causes one dollar worth of damage. Farmer John must visit each one
to install a halter that will calm the cow and stop the damage.
Happily, the cows are positioned in a straight line on a road outside
the farm. FJ can see each of them and knows every cow i’s unique
coordinates (-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. Determine the order that FJ should visit the cows so he
can minimize the total cost of the damage; report the minimum total
damage.
PROBLEM NAME: cowrun
INPUT FORMAT:
* Line 1: A single integer: N
* Lines 2..N+1: Line i+1 contains a single integer: P_i
SAMPLE INPUT (file cowrun.in):
4
-2
-12
3
7
INPUT DETAILS:
Four cows placed in positions: -2, -12, 3, and 7.
OUTPUT FORMAT:
* Line 1: The minimum total cost of the damage.
SAMPLE OUTPUT (file cowrun.out):
50
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.
解题思路
这道有点像剑之修炼,就是让奶牛冷静不用时间。FJ所到之处就是奶牛安静之处。
由于FJ最初在原点,只能左右做往返运动(一称活塞运动)。所以奶牛安静的区域就是一条包括原点的线段。
所以设计状态dp[i][j][k]。其中i表示FJ在负半轴安慰了i之牛,j表示FJ在正半轴安慰的牛数。k=0表示FJ最终位置在最左边的冷静的牛,k=1表示FJ最终在最右边的冷静的牛。
这样子就易得状态转移方程:
dp[i][j][0] = min( dp[i-1][j][0] + (n-i-j+1) * (a1[i-1]-a1[i]) , dp[i-1][j][1] + (n-i-j+1) * (a2[j]-a1[i]) )
dp[i][j][1] = min( dp[i][j-1][0] + (n-i-j+1) * (a2[j]-a1[i]) , dp[i][j-1][1] + (n-i-j+1) * (a2[j]-a2[j-1]) )
边界条件就是 i=0 或 j=0 的时候,这个时候的值是显然的。
我的程序
这个似乎是我第二个非纯水题的C++程序。C++真是简洁美丽啊,但是如果编程习惯不好的话C++便会变得比PASCAL猥琐100倍。
/* ID: sinya1 PROG: cowrun LANG: C++ */ # include <iostream> using namespace std; const int maxn=1001; int i,j,n,n1/*FJ左边的牛数*/,n2/*FJ右边的牛数*/; int t[maxn]/*原始数据*/,a1[maxn]/*FJ左边的牛*/,a2[maxn]/*FJ右边的牛*/; int dp[maxn][maxn][2]; void qsort(const int x,const int y){ int i=x,j=y,sign=t[(x+y)>>1]; do{ while (t[i]<sign) i++; while (t[j]>sign) j--; if (i<=j) swap(t[i++],t[j--]); }while (i<=j); if (x<j) qsort(x,j); if (i<y) qsort(i,y); } void init(){ scanf("%d",&n); for (i=0;i<n;i++) scanf("%d",&t[i]); qsort(0,n-1); a1[0]=0;n1=1; for (i=0;i<n&&t[i]<0;i++) a1[n1++]=t[i]; for (i=1;i<=n1>>1;i++) swap(a1[i],a1[n1-i]); a2[0]=0;n2=1; for (i=n1-1;i<n;i++) a2[n2++]=t[i]; } void work(){ dp[0][0][0]=dp[0][0][1]=0; for (j=1;j<n2;j++) { dp[0][j][1]=dp[0][j-1][1]+(n-j+1)*(a2[j]-a2[j-1]); dp[0][j][0]=dp[0][j][1]+(n-j)*(a2[j]); } for (i=1;i<n1;i++) { dp[i][0][0]=dp[i-1][0][0]+(n-i+1)*(a1[i-1]-a1[i]); dp[i][0][1]=dp[i][0][0]+(n-i)*(-a1[i]); for (j=1;j<n2;j++){ dp[i][j][0]=min( dp[i-1][j][0]+(n-i-j+1)*(a1[i-1]-a1[i]), dp[i-1][j][1]+(n-i-j+1)*(a2[j]-a1[i]) ); dp[i][j][1]=min( dp[i][j-1][0]+(n-i-j+1)*(a2[j]-a1[i]), dp[i][j-1][1]+(n-i-j+1)*(a2[j]-a2[j-1]) ); } } printf("%d\n",min(dp[n1-1][n2-1][0],dp[n1-1][n2-1][1])); } int main(){ freopen("cowrun.in","r",stdin); freopen("cowrun.out","w",stdout); init(); work(); return 0; }