题目分析:
设f[i][j]代表从左侧任意一处到达第i纵列第j高时的最小点击数。i显然有最优子结构和重叠子问题,可以动态规划。
状态]f[i][j],0≤i<n,0<j≤m ,L[i]<j<H[i]可以更新的状态为
f[i+1][k],k∈{k|k=j-y[i] or k=min{j-px[i],m},p∈N,p>0}
依据上式得到的转移方程,最坏复杂度O(nm2)
优化:
当我们从0到n-1枚举i,L[i]+1到H[i]-1枚举j时,我们整理一下上式k的第二种情况,可以发现,当每一维都满足边界条件时:
f[i+1][k]=min{f[i+1][k],f[i+1][k-x[i]]+1}
所以,按照上述方式枚举i和j,利用上条,我们得到一个复杂度为O(nm)的转移方式:
代码细节:
本题细节较多。请参考代码部分。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 8 //variable// 9 int n,m,totp,bottom[10100],top[10100],x[10100],y[10100],f[10100][1010],through=0; 10 bool pip[10100]={0}; 11 12 //solve// 13 int main(){ 14 scanf("%d%d%d",&n,&m,&totp); 15 for (int i=0;i<n;++i){ 16 scanf("%d%d",x+i,y+i); 17 } 18 memset(bottom,0,sizeof bottom); 19 memset(top,127,sizeof top); 20 int P,L,H; 21 for (int i=1;i<=totp;++i){ 22 scanf("%d%d%d",&P,&L,&H); 23 bottom[P]=L;top[P]=H;pip[P]=1; 24 } 25 memset(f,127,sizeof f); 26 memset(f[0]+1,0,sizeof f[0]+1); 27 for (int i=0;i<n;++i){ 28 bool flag=false; 29 for (int j=top[i];j<=m;++j){ 30 f[i][j]=2000000000; 31 } 32 for (int j=bottom[i]+1;j<top[i]&&j<=m;++j){ 33 if (f[i][j]<1000000000){ 34 flag=true; 35 if (pip[i]){ 36 ++through; 37 pip[i]=0; 38 } 39 if (j-y[i]>bottom[i+1]&&j-y[i]<top[i+1]){//// 40 f[i+1][j-y[i]]=min(f[i+1][j-y[i]],f[i][j]); 41 } 42 } 43 } 44 for (int j=bottom[i]+1;j<=m;++j){ 45 if (f[i][j]<1000000000){ 46 int dest=min(j+x[i],m); 47 f[i][dest]=min(f[i][dest],f[i][j]+1); 48 f[i+1][dest]=min(f[i+1][dest],f[i][j]+1); 49 } 50 } 51 if (!flag){ 52 printf("0\n%d\n",through); 53 return 0; 54 } 55 } 56 printf("1\n%d\n",*(min_element(f[n]+1,f[n]+m+1))); 57 return 0; 58 }