题目描述 https://www.luogu.org/problemnew/show/P1941
注意:只有碰到地面和管道才算失败,碰到上顶是可以的。
f[i][j]表示到坐标(i,j)的最优解
当j=m时需要特殊判断,转移方程为
for(int q=m-x[i-1];q<=m;q++)
{
f[i][m]=min(f[i][m],f[i-1][q]+1);
f[i][m]=min(f[i][m],f[i][q]+1);
}
其他情况只要保证j-x[i-1]>0就好了
if(j-x[i-1]>0)
{
f[i][j]=min(f[i][j],f[i-1][j-x[i-1]]+1);
f[i][j]=min(f[i][j],f[i][j-x[i-1]]+1);
}
y不需要分情况,只要j+y[i-1]<=m就行
if(j+y[i-1]<=m)
f[i][j]=min(f[i][j],f[i-1][j+y[i-1]]);
不能走的地方(管道,地面)设为最大值
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=1e4+5,M=1e3+5,maxx=0x3f3f3f3f;
int f[N][M],dn[N],up[N],x[N],y[N],n,m,k;
bool fl[N];
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=0;i<n;i++) scanf("%d%d",&x[i],&y[i]);
for(int i=0;i<=n;i++) dn[i]=0,up[i]=m+1;
for(int i=1;i<=k;i++)
{
int p,d,u;
scanf("%d%d%d",&p,&d,&u);
dn[p]=d,up[p]=u;
fl[p]=1;
}
memset(f,0x3f,sizeof(f));
for(int i=0;i<=m;i++) f[0][i]=0;
int now;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(j==m)
for(int q=m-x[i-1];q<=m;q++)
{
f[i][m]=min(f[i][m],f[i-1][q]+1);
f[i][m]=min(f[i][m],f[i][q]+1);
}
if(j-x[i-1]>0)
{
f[i][j]=min(f[i][j],f[i-1][j-x[i-1]]+1);
f[i][j]=min(f[i][j],f[i][j-x[i-1]]+1);
}
}
for(int j=1;j<=m;j++)
if(j+y[i-1]<=m)
f[i][j]=min(f[i][j],f[i-1][j+y[i-1]]);
for(int j=1;j<=dn[i];j++) f[i][j]=maxx;
for(int j=up[i];j<=m;j++) f[i][j]=maxx;
for(int j=1;j<=m;j++)
if(f[i][j]!=maxx) now=i;
}
int ans=maxx;
for(int i=1;i<=m;i++) ans=min(ans,f[n][i]);
if(ans<maxx)
{
printf("1\n%d",ans);
return 0;
}
ans=0;
for(int i=1;i<=now;i++)
if(fl[i]==1) ans++;
printf("0\n%d",ans);
return 0;
}
’