USACO 2009 Open Grazing2 /// DP+滚动数组oj26223

题目大意:

输入n,s;n头牛 s个栅栏

输入n头牛的初始位置

改变他们的位置,满足

1.第一头与最后一头的距离尽量大

2.相邻两头牛之间的距离尽量满足 d=(s-1)/(n-1),偏差不超过1

3.移动的总步数尽量小

https://blog.csdn.net/BlackJack_/article/details/73527208

首先因需要尽量满足d

1.若整除则全部为d即可

2.若不整除则说明存在偏差,则有些距离 d 有些距离 d+1 即可

除了第一头牛移到1 最后一头牛移到s之外

其余第 i 头牛最佳位置应为 d*(i-1)

若到目前为止位置偏差值为 j ,则应为 d*(i-1)+ j

则这头牛应该移动 | a[ i ]-(d*(i-1)+j)| 即 abs( a[ i ] - ( i-1 ) * d - j ) 

那么可由min( dp[ i-1 ][ j ],dp[ i-1 ][ j-1 ] )转移而来

前者是 i-1 与 i 距离 d 的情况,而后者是 i-1 与 i 距离 d+1 的情况

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
int a[1505], dp[2][1505]; // 滚动数组
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m)) {
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        sort(a+1,a+1+n);
        int d=(m-1)/(n-1);// 最佳间距
        m=m-(n-1)*d;// 总偏差间距+1 (方便推算)
        memset(dp,INF,sizeof(dp));
        /// dp[i][j] 表到第i个时偏差为j的移动次数
        dp[1][1]=a[1]-1;// 偏差从1开始 则m对应的恰好为总偏差间距
        for(int k=2;k<=n;k++) {
            int i=k%2;
            for(int j=1;j<=k&&j<=m;j++)
                dp[i][j]=min(dp[(!i)][j-1],dp[(!i)][j])
                        +abs(a[k]-(k-1)*d-j);
        }
        printf("%d\n",dp[n%2][m]);
    }

    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/zquzjx/p/9286018.html
今日推荐