[01背包]【NOIP2014D1T3】飞扬的小鸟 题解

写在前面:

所有背包类的DP我都最后写成01背包了……已经习惯这么用,3年了……
所以看到小标题写01背包别吃鲸

洛谷传送门在此
UOJ传送门在此

解题分析

不得不说这道题对付我这个PJ组水平蒟蒻还是很有用的。

O ( n m 2 ) O(nm^2) O(nm2)的思路比较简单: f [ i ] [ j ] f[i][j] f[i][j]表示走到第i列第j行至少需要走几步,伪代码如下

for i= 1 ~ n 
    for j= 1 ~ m 
    {
      f[i][j]=f[i-1][j+b[i-1]]
      for k 1 to (m-j)/a[i-1] f[i][j]=min(f[i][j],f[i-1][j-k*a[i-1]]+k)
     }

不过这个复杂度实在不敢恭维,70分有了,100分?做梦!

等一下,那个 ( m − j ) / a [ i − 1 ] (m-j)/a[i-1] (mj)/a[i1]有点眼熟,根据题目可以想一下,这个点击次数理论上是无限的(尽管由于要少点几下不会怎么做),然后记忆里回想一下,这个方程是不是有点眼熟,这个模型……

好吧,这模型就是完全背包啊(不是我自己想出来的),所以可以分开处理向上和向下,向上的部分完全背包解决,然后专门处理 f [ i ] [ m ] f[i][m] f[i][m](快接近顶部,再点一下就到顶部了),然后专门处理向下(这又是个01背包),水管部分最后再刷成INF。转移方程见代码

####复杂度

时间: O ( n m ) O(nm) O(nm)
空间: O ( n m ) O(nm) O(nm),重金求一维或滚动数组解决的~~,价格私信聊~~_

#include
#include
#include
using namespace std;
int n,m,k,INF,ans,cnt,f[10005][1005],a[10005],b[10005],L[10005],R[10005];
inline void readi(int &x){
	x=0; char ch=getchar();
	while ('0'>ch||ch>'9') ch=getchar();
	while ('0'<=ch&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
}
void _init(){
	freopen("bird.in","r",stdin);
	freopen("bird.out","w",stdout);
	readi(n); readi(m); readi(k);
	memset(f,63,sizeof(f)); INF=f[0][0];
	for (int i=1;i<=m;i++) f[0][i]=0;
	for (int i=0;i

你可能感兴趣的:(NOIP题解,01背包)