Trip Plannin 动态规划

4261 - Trip Planning
Asia - Taipei - 2008/2009
PDF   Submit   Ranking

 

 

You are going on a long trip. Initially, you stay at hotel 0. Along the way, there are n hotels. The only place you are allowed to stop are at these hotels. The distance from hotel i - 1 to hotel i is ai . You can choose which of the hotels you stop at. You must stop at the final hotel, which is your destination.

You would ideally like to travel 100 kilometers a day. However, this may not be possible. It depends on the spacing of the hotels. There is no limit on the distance you traveled in a day. If you travel x kilometers during a day, the penalty for that day is (x - 100)2 . You want to plan your trip so as to minimize the total penalty -- that is, the sum, over all travel days, of the daily penalty. Write a program to determine the optimal sequence of hotels at which to stop.


Input 
The input file contains a set of test data. Each test data consists of two parts. The first part is the number of hotels n . The second part is a sequence of n integers a1, a2,..., an . Each ai is the distance between hotel i - 1 and hotel i . Assume that 0 < ai < 200 . They may be written in many lines. Assume that n < 1000 , and n = 0 signals the end of the test data.


Output 
The first line of the output is the minimum penalty p . The second line of the output is the indexes of the hotels to stop at. If the solution is not unique, print the one with fewer stops. If there are more then one solutions with the same number of stops, print the one which is the lexicographically smallest one. For example (1 2 4) < (1 3 4) . Print 30 stops in each line, except the last line which may contain less stops. Print a blank line between datasets.


Sample Input 

10
11 48 28 87 35 86 37 83 16 34
20
81 49 50 87 107 20 40 84 60 47 29 30 35 47 108 41 85 106 77 106
0


Sample Output 

p=2271
 0 3 5 7 10

p=4617
 0 1 3 4 6 8 11 14 15 17 18 19 20

 


#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int main()
{
    int n,a[1010],sum[1010];
    int pre[1010],pl,ans[1010],num[1010];
    long long f[1010];
    int flag=0;
    while(scanf("%d",&n)==1&&n)
    {
        if(flag==0) flag++;
        else printf("/n");
        memset(num,0,sizeof(num));
        for(int i=0;i<=n;i++) pre[i]=i;
        sum[0]=0;f[0]=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            sum[i]=sum[i-1]+a[i];
        }
        for(int i=1;i<=n;i++)
        {
            int t=i-200;if(t<0) t=0;
            f[i]=(sum[i]-sum[t]-100)*(sum[i]-sum[t]-100);pre[i]=t;num[i]=num[t]+1;
            for(int j=t;j<i;j++)
            {
                if(f[i]>f[j]+(sum[i]-sum[j]-100)*(sum[i]-sum[j]-100))
                {
                    f[i]=f[j]+(sum[i]-sum[j]-100)*(sum[i]-sum[j]-100);
                    pre[i]=j;num[i]=num[j]+1;
                }
                else if(f[i]==f[j]+(sum[i]-sum[j]-100)*(sum[i]-sum[j]-100))
                {
                    if(num[j]<num[pre[i]]) pre[i]=j,num[i]=num[j]+1;
                }   
            }
        }
        int l=n;pl=1;ans[0]=n;
        while(pre[l]!=l)
        {
            ans[pl++]=pre[l];
            l=pre[l];
        } 
        cout<<"p="<<f[n]<<endl;
        int cnt=1;
        for(int i=pl-1;i>=0;i--,cnt++)
        {
            printf(" %d",ans[i]);
            if(cnt%30==0) printf("/n");
        }   
        if(cnt%30) printf("/n");
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值