万圣节的小L

万圣节的小L

题目描述:

今天是万圣节,小L同学开始了一年一度的讨要糖果游戏,但是在刚刚过去的比赛中小有成就的他打算给自己增加一点难度:如果没有讨到每一家的糖果就算输。

已知小L共有n(n不大于10000)个邻居,他们都在同一条街上(可以近似看成一条直线),第i个邻居的坐标是xi。L同学的妈妈会在一开始把他送到任意邻居的门前。现在已知所有邻居会在di时间后休息(休息以后不能再去打扰),求访问完所有点的最短时间,如果无解输出“No solution”。

输入格式:

输入第一行为一个正整数表示n,接下来n行,每行两个用空格隔开的数,分别表示第i个邻居的位置和休息时间。

输出格式:

输出一个数,表示最短时间,无解输出“No solution”。

输入样例:

5
1 3
3 1
5 8
8 19
10 15

输出样例:

11


解题思路:

题目一看就是区间dp,但是数据范围n<=10000,普通的dp[i][j]肯定炸,所以这道题的难点就是状态转移,滚动数组正好能解决这个问题

定义一个数组dp[2][100010][2]:

第一维用来滚动,即轮换来记录上一次的状态和这一次的状态 now=last,last^=1

第二维记录位置

第三维记录方向(0左,1右)

依题意可得转移方程

dp[now][j][0]=min(dp[last][j+1][0]+x[j+1]-x[j],dp[last][j+1][1]+x[j+i]-x[j]);

dp[now][j][1]=min(dp[last][j][0]+x[j+i]-x[j],dp[last][j][1]+x[i+j]-x[i+j-1]);


 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<algorithm>
 4 #define inf 0x7ffffff
 5 using namespace std;
 6 int n,now,last,x[10010],d[10010],dp[2][10010][2],ans;
 7 int main()
 8 {
 9     scanf("%d",&n);
10     for(int i=1;i<=n;++i)
11         scanf("%d%d",&x[i],&d[i]);
12     for(int i=1;i<n;++i)
13     {
14         last=now;
15         now^=1;
16         for(int j=1;j<=n-i;++j)
17         {
18             dp[now][j][0]=min(dp[last][j+1][0]+x[j+1]-x[j],dp[last][j+1][1]+x[j+i]-x[j]);
19             dp[now][j][1]=min(dp[last][j][0]+x[j+i]-x[j],dp[last][j][1]+x[i+j]-x[i+j-1]);
20             if(dp[now][j][0]>=d[j])
21                 dp[now][j][0]=inf;
22             if(dp[now][j][1]>=d[i+j])
23                 dp[now][j][1]=inf;
24         }
25     }
26     ans=min(dp[now][1][0],dp[now][1][1]);
27     if(ans==inf)
28         printf("No solution");
29     else
30         printf("%d",ans);
31     return 0;
32 }

猜你喜欢

转载自www.cnblogs.com/__Kgds/p/10049095.html