cqyz oj | 阿里巴巴

Description

  在一条直线上有 n 件珠宝,已知每件珠宝的位置xi,并且第 i 件珠宝在 ti 时刻(单位:秒)就消失,问能否将所有的珠宝收集起来?如果能,求出最短时间。搜集能瞬间完成,但收集的人每秒只能移动一个单位的距离。

Input

  若干组数据,每组数据的第一行为n,表示有n颗珠宝,接下来的n行,每行宝行两个整数:x,t,表示珠宝的位置和消失时间。

Output

  如果有解,则输出一个整数,表示将所有珠宝收集完的最早完成时间,否则输出No solution。

Sample Input 1 

5
1 3
3 1
5 8
8 19
10 15

5
1 5
2 1
3 4
4 2
5 3

Sample Output 1

11
No solution

Hint

n<=10000
0<=x,t<=10^9

网上分析:

f(i,j,0)表示区间i~j中获得所有宝藏并且停留在左端点,f(i,j,1)停留在右端点
ans=min(f(1,n,0),f(1,n,1))
i=j时,f(i,j,0)=f(i,j,1)=0;
f(i,j,0)=min(f(i+1,j,1)+x[i+1]-x[i],f(i+1,j,0)+x[j]-x[i])
f(i,j,1)=min(f(i,j-1,0)+x[j]-x[j-1],f(i,j-1,1)+x[j]-x[i])
填表的时候需要按照主对角线填入

加一个压行不然会爆空间

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 10005, inf = 0x3f3f3f3f;

struct data{
    int x;
    int t;
    bool operator<(const data &b)const{
        return x < b.x;
    }
}a[maxn];

int n;
bool data_in(){
    if(scanf("%d", &n) == 1){
        for(int i=1;i<=n;i++)
            scanf("%d%d", &a[i].x, &a[i].t);
        sort(a+1, a+1+n);
        return true;
    }
    else return false;
}

int f[2][maxn][2];
/*
f[i][j][0] = min(f[i+1][j][0]+x[i+1]-x[i], f[i+1][j][1]+x[j]-x[i])
f[i][j][1] = min(f[i][j-1][0]+x[j]-x[i], f[i][j-1][1]+x[j]-x[j-1])
*/
void solve(){
    memset(f, 0, sizeof(f));
    for(int len=2;len<=n;len++)
        for(int i=1;i+len-1<=n;i++){
            int j=i+len-1;
            f[i&1][j][0] = min(f[(i+1)&1][j][0]+a[i+1].x-a[i].x, f[(i+1)&1][j][1]+a[j].x-a[i].x);
            if(f[i&1][j][0] >= a[i].t) f[i&1][j][0] = inf;
            f[i&1][j][1] = min(f[i&1][j-1][0]+a[j].x-a[i].x, f[i&1][j-1][1]+a[j].x-a[j-1].x);
            if(f[i&1][j][1] >= a[j].t) f[i&1][j][1] = inf;
        }
    int ans = min(f[1][n][0], f[1][n][1]);
    if(ans<inf) printf("%d\n", ans);
    else puts("No solution");
}

int main(){
    while(data_in())
        solve();
    return 0;
}
View Code
posted @ 2019-10-10 18:23  Deguassing-compass  阅读(180)  评论(0编辑  收藏  举报