poj Finicky Grazers 3184 夜

http://poj.org/problem?id=3184

动态规划 加各种优化

二维数组太大 需要用滚动数组

题目大意: 给你N头牛 和(0--L)L+1个位置 在满足牛之间距离最大化的前提下

移动牛花费时间最少

首先第一头牛必须在 0 这个位置 第N 头牛必须在 L 这个位置

D=L/(N-1);

如果L%(N-1) 余数不为 0 时 存在 D+1

本题关键在于 每头牛所在位置 都有一定的范围

用函数 findlr(int i,int &l,int &r)求范围 i代表第几头牛 l和r分别为左右边界

其他详情见代码注释

#include<iostream>
#include<string>
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;

#define MAX 0xfffffff
#define MAXN 10005
#define MAXL 100005
int location[MAXN];
int moveto[2][MAXL];//滚动数组
int D,D1;//D1为(D+1)如果为-1 则代表(D+1)不存在
int N,L;
inline void findlr(int i,int &l,int &r)//求每头牛的边界
{
       if(i<N)
       {
           l=D*(i-1);
           if(D1!=-1&&(L-(D1*(N-i)))>l)
           {
               l=(L-(D1*(N-i)));
           }
           r=L-(D*(N-i));
           if(D1!=-1&&(D1*(i-1))<r)
           {
               r=(D1*(i-1));
           }
       }
       else//最后一头牛位置确定
       {
           l=r=L;
       }
}
int main()
{
    scanf("%d%d",&N,&L);
    for(int i=1;i<=N;++i)
    {
        scanf("%d",&location[i]);
    }
    if(N==1)
    {
        printf("0\n");
        return 0;
    }
    D=L/(N-1);
    if(L%(N-1))
    {
        D1=D+1;
    }
    else
    {
        D1=-1;
    }
    for(int i=0;i<2;++i) //先初始化最大
    {
        for(int j=0;j<=L;++j)
        {
            moveto[i][j]=MAX;
        }
    }
    int l,r,l1,r1;
    moveto[1][0]=abs(location[1]-0);//第一头牛位置提前求出来
    for(int i=2;i<=N;++i)//从第二头牛开始求
    {
       findlr(i,l,r);//发现的i头牛所在位置范围
       for(int j=l;j<=r;++j)
       {
          moveto[i%2][j]=moveto[(i-1)%2][j-D]+abs(location[i]-j);
          if(D1!=-1&&j-D1>=0)//存在第二种可能(j-D1)是防止小于0而越界
          {
             moveto[i%2][j]=min(moveto[i%2][j],moveto[(i-1)%2][j-D1]+abs(location[i]-j));
          }
       }
       if(i>3)
       {
           findlr(i-2,l1,r1);//由于用了滚动数组 i和(i-2)所用的一样 所用需要将i所在范围以外的进行初始化回避(i-2)的影响
           for(int w=l1;w<=r1;++w)
           {
               if(w<l||w>r)
               {
                   moveto[i%2][w]=MAX;
               }
           }
       }
    }
    printf("%d\n",moveto[N%2][L]);
    return 0;
}

原文地址:https://www.cnblogs.com/liulangye/p/2437353.html