#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=10005;
const int M=1005;
int n,m,k,sum,ans=1e9,X[N],Y[N];
int up[N],down[N],bj[N],f[N][M];
inline bool check(int i){
for(int j=1;j<=m;++j)
if(f[i][j]!=1e9)return 1;
return 0;
}
int main(){
n=read();m=read();k=read();
for(int i=0;i<n;++i)up[i]=read(),down[i]=read();
for(int i=1;i<=k;++i){
int pos=read();bj[pos]=1;X[pos]=read();Y[pos]=read();
}
for(int i=1;i<=n;++i)
for(int j=0;j<=m;++j)f[i][j]=1e9;
//i=0时任一位置都是0步,因为题目说了可以从最左边任意整数高度位置出发,其余初始化正无穷
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
if(j-up[i-1]>=1){
f[i][j]=min(f[i][j],f[i-1][j-up[i-1]]+1);//跳一次
f[i][j]=min(f[i][j],f[i][j-up[i-1]]+1);//连着跳
}
}
for(int j=m-up[i-1];j<=m;++j){//飞到顶部的时候要单独考虑
f[i][m]=min(f[i][m],f[i-1][j]+1);//跳一次
f[i][m]=min(f[i][m],f[i][j]+1);//连着跳
}
for(int j=1;j+down[i-1]<=m;++j)//不跳,直接下降过来
f[i][j]=min(f[i][j],f[i-1][j+down[i-1]]);
//不能把不跳的情况与跳的情况一起更新,而要先更新跳再更新不跳,因为会出现以下这种情况:
//(i,j)可以从(i-1,j+down[i-1)转移过来,但不能从(i-1,j-up[i-1])转移过来
//如果我们放一起,那么更新连跳的时候的f[i][j-up[i-1]]可能是从上一次下降过来的
//相当于你这一次做的动作是从(i-1,j+down[i-1])下降到(i,j),又从(i,j)上升到(i,j+up[i-1]),显然不合法
if(bj[i]){//如果这个地方是管子
for(int j=0;j<=X[i];++j)f[i][j]=1e9;
for(int j=Y[i];j<=m;++j)f[i][j]=1e9;//这些地方都不能走,还原为正无穷
int flag=0;
for(int j=X[i]+1;j<=Y[i]-1;++j)
if(f[i][j]!=1e9){flag=1;break;}//查找是否有能走的地方
if(flag)++sum;//sum记录通过的管子数量
else{printf("0\n%d\n",sum);return 0;}
}
else if(!check(i)){printf("0\n%d\n",sum);return 0;}
}
for(int j=1;j<=m;++j)ans=min(ans,f[n][j]);//找到最小的合法地方
printf("1\n%d\n",ans);
return 0;
}
原文:https://www.cnblogs.com/PPXppx/p/11700540.html