uva1336 Fixing the Great Wall

https://vjudge.net/problem/UVA-1336

显然最佳的移动方式一定是向左走一段,向右走一段,再向左走一段,再向右走一段......(或者反过来)

无论如何中间的会最先被修理好,所以考虑区间dp

$f_{i,j,0/1}$表示修理好了$i\rightarrow j$时,所用的最小费用(注意费用提前计算)

预处理处$cl_{i,j}(i\leq j)$表示从$i$出发修理到$j$的费用

$cr_{i,j}(i\geq j)$从$i$出发修理到$j$的费用

然后就是转移了(其实还是很好想的),由于决策集合不会变小,所以可以用一个标记记录一下最小值,$O(1)$转移

#include<bits/stdc++.h>
using namespace std;
const int N=1005;
const double inf=1000000000.0,eps=0.000001;
int n,v,x,st;
struct node{int c,d,x;} sec[N];
double f[N][N][2],cl[N][N],cr[N][N];
double sum[N],min0[N],min1[N],bs;
void clear()
{
    st=0,bs=0;
    for(int i=0;i<N;++i)
    {
        sum[i]=0,cl[i][i]=0;
        min0[i]=min1[i]=inf;
    }
}
double tme(int a,int b) {return (double)abs(sec[a].x-sec[b].x)/(double)v;}
bool cmp(node a,node b) {return a.x<b.x;}
int main()
{
    while (scanf("%d%d%d", &n, &v, &x)==3 && n)
    {
        if(!n && !v && !x) return 0;
        clear();
        for(int i=1;i<=n;++i)
            scanf("%d%d%d",&sec[i].x,&sec[i].c,&sec[i].d);
        sort(sec+1,sec+n+1,cmp);
        sec[n+1].x=x+1;
        for(int i=1;i<=n+1;++i)
            if(sec[i].x>x) {st=i-1;break;}
        for(int i=1;i<=n;++i)
            for(int j=i+1;j<=n;++j)
                cl[i][j]=cl[i][j-1]+tme(i,j)*sec[j].d;
        for(int i=1;i<=n;++i)
            for(int j=i-1;j>=1;--j)
                cr[i][j]=cr[i][j+1]+tme(i,j)*sec[j].d;
        for(int i=1;i<=n;++i) sum[i]=sum[i-1]+sec[i].d,bs+=sec[i].c;
        if(!st) {
            printf("%.0lf\n",floor(bs+cl[1][n]+1.0*(sec[1].x-x)/(1.0*v)*sum[n]+eps));
            continue;
        }
        if(st==n) {
            printf("%.0lf\n",floor(bs+cr[n][1]+1.0*(x-sec[n].x)/(1.0*v)*sum[n]+eps));
            continue;
        }
        f[st][st][0]=f[st][st][1]=1.0*(x-sec[st].x)/(1.0*v)*sum[n];
        f[st+1][st+1][0]=f[st+1][st+1][1]=1.0*(sec[st+1].x-x)/(1.0*v)*sum[n];
        min0[st]=min1[st]=f[st][st][0];
        min0[st+1]=min1[st+1]=f[st+1][st+1][0];
        for(int i=2;i<=n;++i)
            for(int j=max(1,st-i+1);j<=st+1 && i+j-1<=n;++j)
            {
                int l=j,r=j+i-1;
                double pre=sum[n]-sum[r]+sum[l-1];
                f[l][r][0]=min0[r]+cr[r][l]+tme(r,l)*pre;
                f[l][r][1]=min1[l]+cl[l][r]+tme(r,l)*pre;
                min0[r]=min(min0[r],f[l][r][1]-cr[r][l]);
                min1[l]=min(min1[l],f[l][r][0]-cl[l][r]);
                //cout<<l<<" "<<r<<" "<<f[l][r][0]<<" "<<f[l][r][1]<<endl;
            }
        printf("%.0lf\n",floor(min(f[1][n][0],f[1][n][1])+bs+eps));
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/w19567/p/11314962.html