【UVa】【DP】1632 Alibaba

本文解析了UVa1632 Alibaba问题,通过区间动态规划的方法解决了一个阿里巴巴访问特定位置的问题。文章详细介绍了状态定义、状态转移方程及边界条件,并给出了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

UVa 1632 Alibaba

题目

◇题目传送门◆(由于UVa较慢,这里提供一个vjudge的链接)
◇题目传送门(vjudge)◆

题目大意

x x 轴上有N个点,其中第 i i 个点的位置为xi,且它在第 di d i 秒后会消失。Alibaba可以从任意一点出发,且移动一个单位长度需要花一秒。求Alibaba访问完所有点的最短时间,无解时输出No solution。

思路

我们可以贪心地想,若我们在访问完区间 [i,j] [ i , j ] 中的点后,必然会位于点 i i 或点j。所以,我们就将这道题转化为了区间DP。

定义状态 f[i][j][0/1] f [ i ] [ j ] [ 0 / 1 ] 为访问完区间 [i,j] [ i , j ] 中的点后, 0 0 表示位于i点, 1 1 表示位于j点。

则得出状态转移方程:

f[i][j][k]={min(f[i+1][j][0]+a[i+1]a[i],f[i+1][j][1]+a[j]a[i])min(f[i][j1][0]+a[j]a[i],f[i][j1][1]+a[j]a[j1])k=0k=1 f [ i ] [ j ] [ k ] = { min ( f [ i + 1 ] [ j ] [ 0 ] + a [ i + 1 ] − a [ i ] , f [ i + 1 ] [ j ] [ 1 ] + a [ j ] − a [ i ] ) k = 0 min ( f [ i ] [ j − 1 ] [ 0 ] + a [ j ] − a [ i ] , f [ i ] [ j − 1 ] [ 1 ] + a [ j ] − a [ j − 1 ] ) k = 1

其中 1iN,i+1jN 1 ≤ i ≤ N , i + 1 ≤ j ≤ N

解释一下:

首先对于状态 f[i][j][0] f [ i ] [ j ] [ 0 ] ,此时Alibaba需要走到点 i i ,画个图解释一下:

则对于状态f[i][j][0],在 f[i+1][j][0]+a[i+1]a[i],f[i+1][j][1]+a[j]a[i] f [ i + 1 ] [ j ] [ 0 ] + a [ i + 1 ] − a [ i ] , f [ i + 1 ] [ j ] [ 1 ] + a [ j ] − a [ i ] 之间取最小值即可。

对于状态 f[i][j][1] f [ i ] [ j ] [ 1 ] ,我们还是画个图解释:

即在 f[i][j1][0]+a[j]a[i],f[i][j1][1]+a[j]a[j1] f [ i ] [ j − 1 ] [ 0 ] + a [ j ] − a [ i ] , f [ i ] [ j − 1 ] [ 1 ] + a [ j ] − a [ j − 1 ] 之间取最小值。

接下来就是最后一步:

如何判断无解?

若在计算某一状态时发现当前所处的点的时间已经超出了这个点的 d d ,则将该状态赋值为INF。

最后判断min(f[1][N][0],f[1][N][1])是否大于等于INF即可。

正解代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int Maxn=10000;
const int INF=0x3f3f3f3f;

int N,p[Maxn+5],d[Maxn+5];
int f[Maxn+5][Maxn+5][2];

int main() {
    #ifdef LOACL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    while(scanf("%d",&N)!=EOF) {
        for(int i=1;i<=N;i++)
            scanf("%d %d",&p[i],&d[i]);
        for(int i=1;i<=N;i++)
            f[i][i][0]=f[i][i][1]=0;//访问区间[i,i]时所需时间为0
        for(int i=N-1;i>=1;i--)
            for(int j=i+1;j<=N;j++) {
                f[i][j][0]=min(f[i+1][j][0]+p[i+1]-p[i],f[i+1][j][1]+p[j]-p[i]);
                if(f[i][j][0]>=d[i])f[i][j][0]=INF;
                f[i][j][1]=min(f[i][j-1][0]+p[j]-p[i],f[i][j-1][1]+p[j]-p[j-1]);
                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)puts("No solution");
        else printf("%d\n",ans);
        memset(f,0,sizeof f);
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值