Alibaba

Alibaba the famous character of our childhood stories would like to be immortal in order to keep
bringing happiness to children. In order to rich this status he needs to prove that he is still able to
do some unusual things. There are n treasures, (n ≤ 10000) each in a different place located along
a straight road. Each treasure has a time limit, after that it vanishes. Alibaba must take all the n
treasures, and he must do it quickly. So he needs to figure out the order in which he should take the
treasures before their deadlines starting from the most favorable position. Alibaba has the list of places
and deadlines of the treasures. A place i is located at distance di from the leftmost end of the road.
The time it takes to take a treasure is instantaneous. Alibaba must find the smallest time by which he
can take all the treasures.

Input

The program input is from a text file. Each data set in the file stands for a particular set of treasures.
For each set of treasures the input contains the number of treasures, and the list of pairs place - deadline
in increasing order of the locations. White spaces can occur freely between the numbers in the input.
The input data are correct. For each set of data the program prints the result to the standard output
on a separate line. The solution is represented by the smallest time by which Alibaba can take all the
treasures before they vanish. If this is not possible then the output is ‘No solution’.

Sample Input

5
1 3
3 1
5 8
8 19
10 15
5
1 5
2 1
3 4
4 2
5 3

Sample Output

11
No solution

题目大意

给出n个在x轴上的点的下标与它消失的时间,每个点都以从左至右的下标给出。
你可以任选一个地方作为起点,问:你能否经过所有的点,若能,则你所需的最短时间。

思路

由于有一个x轴下标,我们可以想一想区间dp。
dp[i][j]:取完第i个点与第j个点之间所有的点所需的最短时间。
状态定义很清楚,但该如何转移呢?
即使在i~j之间枚举k,也不能找到其关系。
一个区间至另一个相邻的区间的起始点应为左区间右端点与右区间左端点。
但我们却并不知道其是否是最优解,可能存在重复走情况,无法转移,且时间也不允许n^3。
所以我们可以只考虑(i+1,j)与(i,j-1)的区间,最优情况的终点必定在区间端点。
但由于不知道最优情况的终点在左还是在右,我们可以再开一维来表示终点位置。

由于数据太坑,建议将0与1放在最后一维用来优化时间。

代码

#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=10000+5;
const int INF=0X3F3F3F3F;
int n,x[MAXN],d[MAXN];
int f[MAXN][MAXN][2];
int main(){
    while(~scanf("%d",&n)){
        for(int i=1;i<=n;i++){
            scanf("%d %d",&x[i],&d[i]);
            f[i][i][0]=f[i][i][1]=0;
        }
        for(int l=2;l<=n;l++)
            for(int i=1;i+l-1<=n;i++){
                int j=i+l-1;
                f[i][j][0]=min(f[i+1][j][0]+x[i+1]-x[i],f[i+1][j][1]+x[j]-x[i]);
                if(f[i][j][0]>=d[i]) f[i][j][0]=INF;
                f[i][j][1]=min(f[i][j-1][1]+x[j]-x[j-1],f[i][j-1][0]+x[j]-x[i]);
                if(f[i][j][1]>=d[j]) f[i][j][1]=INF;
            }
        int Ans=min(f[1][n][0],f[1][n][1]);
        if(Ans!=INF)printf("%d\n",Ans);
        else printf("No solution\n");
    }
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值