不能让老婆累着了,所以把另一个交给黑子。
秀老婆!!秀老婆!!(第二个不是)
知识点
动态规划
动态规划、滚动数组
基本思路
用f[i%2][j]表示到达第i列高度为j的点最少需要跳几次
读入,记录柱子
以横坐标为枚举对象,开始递推
初始化下一列的数组(因为用的是滚动数组)
枚举当前列可达的点
分向上跳和向下落更新
输出
详细解释
状态设计
用f[i%2][j]表示到达第i列高度为j的点最少需要跳几次
读入,记录柱子
用两个数组去保存每个柱子的上限和下限
用数组vis[i]去保存坐标为i的柱子的下标(我们的上限和下限是按顺序存放的)
如果没有,就是-1
(这里也提供一个不同的保存方法,就是不用vis,对于没有柱子的地方,把上限和下限设置为最大值和0,判断的时候可能会简单一点)
以横坐标为枚举对象
我们这里递推以横坐标为对象,而且我们可以看出来,一列的状态,只与前面一列相关,与再往前的就不相关了,所以我们可以采用滚动数组来做。用i%2表示当前列,(i+1)%2表示下一列。
注意,我们要在每次枚举之初设置一个标志变量flag,默认为0
如果扫描到当前列有可达点,就变为1
因为我们有可能会遇到死在半路的情况。
初始化下一列数组
我们采取的策略是用当前列去更新下一列,所以我们要将下一列的数组全部赋值为最大值,便于我们更新。
枚举当前列可达的点
因为我们是由当前列上的点跳到下一列,所以一定要可达才能跳。
能跳的条件就是小于我们初始化的最大值
分向上跳和向下落更新
我们先说向下跳,因为这个很简单。
只要判断别砸到柱子上就好了。
下面我们再看向上跳。
值得注意的是我们向上跳,可以跳多次,不是只能跳一次
我们需要判断在不在柱子之间。
然后结束条件是撞到天花板,或者砸到柱子的上沿
这样就可以了。
如果有flag==0的情况,那就用endx记录结束的列即可。
输出
判断有没有提前结束,然后分情况输出就好了。
难度点评
不算很难,代码写起来似乎复杂一些,不过还是很水。
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int f[2][1005];
int n,m;
int k;
int vis[10005];
int L[10005],H[10005];
int X[10005],Y[10005];
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=0;i<n;i++){
scanf("%d%d",&X[i],&Y[i]);
}
memset(vis,-1,sizeof(vis));
for(int i=0;i<k;i++){
int in;
scanf("%d%d%d",&in,&L[i],&H[i]);
vis[in]=i;
}
memset(f,0x3f,sizeof(f));
for(int i=1;i<=m;i++){
f[0][i]=0;
}
int endx=-1,flag=0;
for(int i=0;i<n;i++){
flag=0;
for(int j=1;j<=m;j++){
f[(i+1)%2][j]=0x3f3f3f3f; //初始化
}
for(int j=m;j>=1;j--){
if(f[i%2][j]<0x3f3f3f3f){
flag=1;
int h=j+X[i];
if(h>m){
if(vis[i+1]==-1){
f[(i+1)%2][m]=min(f[(i+1)%2][m],f[i%2][j]+1);
}
}
if(X[i])while(h<=m){
if(vis[i+1]!=-1){
if(h>L[vis[i+1]]&&h<H[vis[i+1]]){
if(f[(i+1)%2][h]<=f[i%2][j]+(h-j)/X[i]){
break;
}else{
f[(i+1)%2][h]=f[i%2][j]+(h-j)/X[i];
}
}else if(h>=H[vis[i+1]]){
break;
}
}else{
if(f[(i+1)%2][h]<=f[i%2][j]+(h-j)/X[i]){
break;
}else{
f[(i+1)%2][h]=f[i%2][j]+(h-j)/X[i];
}
}
if(h==m){
break;
}
h+=X[i];
if(h>m){
if(vis[i+1]==-1){
f[(i+1)%2][m]=min(f[(i+1)%2][m],f[i%2][j]+(h-j)/X[i]);
break;
}
}
}
if(j-Y[i]>=1){
if(vis[i+1]!=-1){
if(j-Y[i]>L[vis[i+1]]&&j-Y[i]<H[vis[i+1]]){
f[(i+1)%2][j-Y[i]]=min(f[(i+1)%2][j-Y[i]],f[i%2][j]);
}
}else{
f[(i+1)%2][j-Y[i]]=min(f[(i+1)%2][j-Y[i]],f[i%2][j]);
}
}
}
}
if(flag==0){
endx=i-1;
break;
}
}
if(endx>-1){
int num=0;
for(int i=0;i<=endx;i++){
if(vis[i]>-1){
num++;
}
}
printf("0\n%d",num);
}else{
int ans=0x3f3f3f3f;
for(int i=1;i<=m;i++){
ans=min(ans,f[n%2][i]);
}
printf("1\n%d",ans);
}
return 0;
}