题解:首先设置一个状态dp[i][j]表示到达位置i高度为j的最小点击次数。
我们讨论一下:
在i-1为位置跳的情况----
(1)
cap[i][j]=min(cap[i][j],cap[i-1][j-up[i-1]]+1);//由i-1位置跳一次而来
cap[i][j]=min(cap[i][j],cap[i][j-up[i-1]]+1);//可以解决多次点击的叠加效果(自己理解一下)(2)
for(int p=j-up[i-1];p<=m;p++)//当当前的高度为m时,显然可以由i-1位置的高度从j-up[i-1]到m到的状态转移过来
{ cap[i][j]=min(cap[i][j],cap[i-1][p]+1); cap[i][j]=min(cap[i][j],cap[i][p]+1); }下落的情况------
for(int j=L[i]+1;j<=H[i]-1;j++)
{ if(j+down[i-1]<=m) cap[i][j]=min(cap[i][j],cap[i-1][j+down[i-1]]); }以下是代码。
#include#include #include #include #include #include #include #include #include #include #define MAXN 10010#define LL long long intusing namespace std;const int INF=1e9;const int EPS=1e-8;struct node{ int l; int h; int w;}t[MAXN];int cap[10001][1001];//到达横坐标为i高度为j的地方的最小步数int n,m,k;int w[MAXN];int L[MAXN],H[MAXN];int up[MAXN],down[MAXN];int main(){ freopen("1.in","r",stdin); freopen("1.out","w",stdout); scanf("%d%d%d",&n,&m,&k); for(int i=0;i<=n-1;i++) scanf("%d%d",&up[i],&down[i]); for(int i=0;i<=n;i++) L[i]=0,H[i]=m+1; int p,l,h; for(int i=1;i<=k;i++) { scanf("%d%d%d",&p,&l,&h); t[i].w=p;t[i].l=l;t[i].h=h; w[p]=1; L[p]=l; H[p]=h; } for(int i=1;i<=n;i++) for(int j=0;j<=m;j++) cap[i][j]=INF; cap[0][0]=INF; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(j>=up[i-1]) { cap[i][j]=min(cap[i][j],cap[i-1][j-up[i-1]]+1); cap[i][j]=min(cap[i][j],cap[i][j-up[i-1]]+1); } if(j==m) { for(int p=j-up[i-1];p<=m;p++) { cap[i][j]=min(cap[i][j],cap[i-1][p]+1); cap[i][j]=min(cap[i][j],cap[i][p]+1); } } } for(int j=L[i]+1;j<=H[i]-1;j++) { if(j+down[i-1]<=m) cap[i][j]=min(cap[i][j],cap[i-1][j+down[i-1]]); } for(int j=1;j<=L[i];j++) cap[i][j]=INF; for(int j=H[i];j<=m;j++) cap[i][j]=INF; } int ans=INF,tot=k; for(int i=n;i>=1;i--) { for(int j=L[i]+1;j<=H[i]-1;j++) if(cap[i][j]