题目描述
贝茜有 C ( 1≤C≤1000 )门科目的作业要上交,之后她要去坐巴士和奶牛同学回家。
每门科目的老师所在的教室排列在一条长为 H( 1≤H≤1000 )的走廊上,他们只在课后接收作业,交作业不需要时间。贝茜现在在位置0,她会告诉你每个教室所在的位置,以及走廊出口的位置。她每走1个单位的路程,就要用1秒。她希望你计算最快多久以后她能交完作业并到达出口。
输入格式
第一行:三个整数 C,H 和 B,1≤C≤1000,1≤H≤1000,0≤B≤H
第二行到 C+1 行:第 i+1 行有两个整数 Xi 和 Ti,0≤Xi≤H,0≤Ti≤10000。
B 表示车站位置。
Xi 表示第 ii 份作业应该在 Xi 这个位置交。
Ti 表示这个位置(教室)的这个科目老师(也就是收这份作业的老师)下课的时间。
输出格式
单个整数,表示贝西交完作业后走到车站的最短时间
样例 #1
样例输入 #1
4 10 3
8 9
4 21
3 16
8 12
样例输出 #1
22
提示
走到坐标 8 处,第 9 分钟交一本作业,等到第 12 分钟时,交另一本作业。再走到坐标 4 处交作业,最后走到坐标 3 处,交最后一本作业,此地就是车站所在位置,共用时 22 分钟
思路
其实就是一道很裸的区间dp + 贪心,我们分成两部分考虑
一:贪心
最佳策略应该是由下面两种状态转移过来的
-
向左或向右移动到 下一个教室 交作业
-
从一个端点移动到另一个端点
如果先去中间某个教室,之后必然还要走到i教室和j教室,那么不如先去i教室或者j教室,之后去另一端的教室时必然会经过中间的教室交作业。
二:区间dp
先把教室按照x轴上的坐标排序
struct ff
{
int x,t;
} a[10000001];
bool cmp(ff xx,ff yy)
{
return xx.x < yy.x;
}
cin>>c>>h>>b;
for(int i = 1; i <= c; i++) cin>>a[i].x>>a[i].t;
sort(a + 1,a + 1 + c,cmp);
我们用dp[i][j][0/1]表示区间i~j还未提交作业,下一步将提交i或j点的作业所需的最短时间。
这样就能写出状态转移方程
for(int i = 1; i <= c; i++)
for(int j = c; j >= i; j--)
{
dp[i][j][0] = min(dp[i][j][0],max(dp[i - 1][j][0] + a[i].x - a[i - 1].x,a[i].t));
dp[i][j][0] = min(dp[i][j][0],max(dp[i][j + 1][1] + a[j + 1].x - a[i].x,a[i].t));
dp[i][j][1] = min(dp[i][j][1],max(dp[i][j + 1][1] + a[j + 1].x - a[j].x,a[j].t));
dp[i][j][1] = min(dp[i][j][1],max(dp[i - 1][j][0] + a[j].x - a[i - 1].x,a[j].t));
}
注意:这里j需要倒序枚举,因为dp[i][j][1 / 0]是由dp[i / i - 1][j / j + 1][0 / 1]转移而来的。
for(int i = 1; i <= c; i++)
for(int j = c; j >= i; j--)
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int c,h,b,dp[2001][2001][2],ans = 1e9;
/*
dp[i][j][0/1]表示区间i~j还未提交作业
下一步将提交i或j点的作业所需的最短时间
*/
struct ff
{
int x,t;
} a[10000001];
bool cmp(ff xx,ff yy)
{
return xx.x < yy.x;
}
signed main()
{
cin>>c>>h>>b;
for(int i = 1; i <= c; i++) cin>>a[i].x>>a[i].t;
sort(a + 1,a + 1 + c,cmp);
memset(dp,0x3f,sizeof(dp));
dp[1][c][0] = max(a[1].x,a[1].t);
dp[1][c][1] = max(a[c].x,a[c].t);
for(int i = 1; i <= c; i++)
for(int j = c; j >= i; j--)
{
dp[i][j][0] = min(dp[i][j][0],max(dp[i - 1][j][0] + a[i].x - a[i - 1].x,a[i].t));
dp[i][j][0] = min(dp[i][j][0],max(dp[i][j + 1][1] + a[j + 1].x - a[i].x,a[i].t));
dp[i][j][1] = min(dp[i][j][1],max(dp[i][j + 1][1] + a[j + 1].x - a[j].x,a[j].t));
dp[i][j][1] = min(dp[i][j][1],max(dp[i - 1][j][0] + a[j].x - a[i - 1].x,a[j].t));
}
for(int i = 1; i <= c; i++)
{
int t = min(dp[i][i][0],dp[i][i][1]) + abs(a[i].x - b);
ans = min(ans,t);
}
cout<<ans;
return 0;
}
怎么样?听懂了吗?如果听懂了就请点赞收藏加关注支持一下吧!您的支持是我继续坚持下去的动力!