一道动态规划题

fanster28_ 2010-08-04 10:04:53
n个球 v1 v2 .... vn vi是球i的大小
m个盒子 容量都是V 且满足 vi<=V ;1<=n,m,V<=500
且不能把球u放到盒子 p, 球 v 放到盒子 q ,当 u > v 且 p< q

问最多能放多少个球

http://zuojie.3322.org:88/soj/problem.action?id=2939

我只能写个n*m*V的,结果TLE了
...全文
381 19 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
绿色夹克衫 2010-08-07
  • 打赏
  • 举报
回复
嗯,好像飞雪也是川大的,很牛呀,更牛的是,好像他学习算法也就是这两年的事儿,进步神速。
不过LZ这方面的天赋也挺强的。
power721 2010-08-07
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 fanster28_ 的回复:]
上面的那样想实现的代码及其繁琐
刚刚看了飞雪给的一篇文章之后发现稍微改一下,本质一样,实现要简单清晰很多
鄙视自己,就这一点会浪费n多时间 ~.~
dp[i][j]表示前i个中选j个需要的最少盒子为(a,b) a个盒子外加b的空间
这样写出来的代码简单很多,也要高效一些


C/C++ code

//dp[i][j]=(a,b) 表示前i个球中选j个球所需的最少盒子为a个加附加……
[/Quote]

Rint()难道是川大的专用函数?
这个是你写的吧
int Rint() { struct X{ int dig[256]; X(){for(int i='0';i<='9';++i) dig[i]=1; dig['-']=1;}}; static X fuck;int s = 1, v = 0, c; for (;!fuck.dig[c = getchar()];); if (c=='-') s=0; else if (fuck.dig[c]) v=c-48; for (;fuck.dig[c=getchar()]; v=v*10+c-48); return s?v:-v;}
fanster28_ 2010-08-07
  • 打赏
  • 举报
回复
有些GCC老版本处理inline static object 有效率问题
fanster28_ 2010-08-07
  • 打赏
  • 举报
回复
现在oj上读入优化没啥用了
fanster28_ 2010-08-06
  • 打赏
  • 举报
回复
上面的那样想实现的代码及其繁琐
刚刚看了飞雪给的一篇文章之后发现稍微改一下,本质一样,实现要简单清晰很多
鄙视自己,就这一点会浪费n多时间 ~.~
dp[i][j]表示前i个中选j个需要的最少盒子为(a,b) a个盒子外加b的空间
这样写出来的代码简单很多,也要高效一些


//dp[i][j]=(a,b) 表示前i个球中选j个球所需的最少盒子为a个加附加的b空间 b<=V
#include <iostream>
#include <cstring>
inline int Rint() {int x;scanf("%d%d",&x);return x;}
const int N=501,one=(1<<10),low=one-1,high=~low;
int dp[N][N],n,m,V,v[N],i,j,t,ans;
#define min(x,y) (x<y?x:y)

inline int addl(int a, int b) {
if ((a&low) + b <= V)
return a + b;
else return (a&high)+one + b;
}

int main() {
for (int cas=Rint();cas--;) {
n=Rint(),m=Rint(),V=Rint();
m=(m<<10);//(m,0)
for (i=1;i<=n;++i) v[i]=Rint();
for (i=1;i<=n;++i) {
dp[i][0]=0; //(0,0)
for (j=1;j<i;++j) {
dp[i][j]=min(dp[i-1][j],addl(dp[i-1][j-1],v[i]));
}
dp[i][i]=addl(dp[i-1][j-1],v[i]);
}
for (ans=0,i=1;i<=n;++i) if (dp[n][i]<m&&i>ans) ans=i;
printf("%d\n",ans);
}
return 0;
}
michael122 2010-08-06
  • 打赏
  • 举报
回复
绿色夹克衫 2010-08-06
  • 打赏
  • 举报
回复
恩,很厉害,DP果然是算法中最灵活有趣的部分,最优子结构的找法决定了复杂度。
前段时间有道的火柴棍那道题也类似,不过比这个还简单一些。

[Quote=引用 12 楼 fanster28_ 的回复:]
是可以优化的,不过不优化也能过,只不过这个最优子结构不好发现

dp[i][j]表示前i个球装j个使用的箱子个数的最小值
lev[i][j]用来记录此时当前箱子剩余容量的最大值
[/Quote]
fanster28_ 2010-08-06
  • 打赏
  • 举报
回复
是可以优化的,不过不优化也能过,只不过这个最优子结构不好发现

dp[i][j]表示前i个球装j个使用的箱子个数的最小值
lev[i][j]用来记录此时当前箱子剩余容量的最大值

dp[i][j] = min(dp[i-1][j], dp[i-1][j-1]+(lev[i-1][j-1]>=v[i])?0:1)
各种情况对应的lev lev[i-1][j] lev[i-1][j-1]-v[i] V-v[i]

dp[n][i]不超过m中i的最大值即为解

O(n^2)
绿色夹克衫 2010-08-05
  • 打赏
  • 举报
回复
可以看看mysword同志的Blog,讲的比较细。

http://blog.csdn.net/mysword/archive/2010/01/08/5154522.aspx

不过说实话,我只是知道方向,自己没真正写过代码。

对应本题就是:前i个盒子装前j个球装满的情况下可以装k个,如果存在前i个盒子装前j'个球装满的情况下可以装k个,j' < j,则后者是个更优的解,同样如果存在前i'个盒子装前j个球装满的情况下可以装k个,i' < i,则后者也是个更优的解。

具体优化到m*n*log(n)的实现,可以看看相关资料,大概是这个意思。

[Quote=引用 10 楼 michael122 的回复:]
正好可以优化这类DP问题。
[/Quote]
michael122 2010-08-05
  • 打赏
  • 举报
回复
仔细讲讲?

[Quote=引用 8 楼 litaoye 的回复:]

刚发现上面回复的问题:

四角不等式 =》
四边不等式

正好可以优化这类DP问题。
[/Quote]
michael122 2010-08-05
  • 打赏
  • 举报
回复
晕,我看错了。。。
原来每个盒子的容积都一样。。 我以为也是变量了


[Quote=引用 7 楼 fanster28_ 的回复:]

你这个跟我的是一模一样的,要TLE,我随机生成的一组数据都要几秒才能出结果

其实他提到的那个是对的

第i个球显然不能放在i后面的盒子里面

因为 vi<=V i个盒子必然可以装下i个球
[/Quote]
绿色夹克衫 2010-08-04
  • 打赏
  • 举报
回复
刚发现上面回复的问题:

四角不等式 =》
四边不等式

正好可以优化这类DP问题。
fanster28_ 2010-08-04
  • 打赏
  • 举报
回复
你这个跟我的是一模一样的,要TLE,我随机生成的一组数据都要几秒才能出结果

其实他提到的那个是对的

第i个球显然不能放在i后面的盒子里面

因为 vi<=V i个盒子必然可以装下i个球
michael122 2010-08-04
  • 打赏
  • 举报
回复
你第一条假设就显然不对
这题的本质是对vi的n个数按顺序分成m段,第i段放入第i个盒子里,i从1到m
一个连续的段放入一个盒子的方法就是对这个段排序,从小往大了放,就能放最多
然后题目就是求这个最优的分段,所得每段放入第i个盒子的数目总和最大
定义一个函数 f(i,j) 表示1到i个盒子放v1到vj个球,最多能放的个数,则f(m,n)就是答案
要首先求出ai(p,q) 表示第i个盒子放vp到vq这些球,能放的最多个数
则 f(i,j)=max {f(i-1,k)+ai(k+1,j)} k从0到j
这样的复杂度跟lz的差不多,不过感觉还可以大大优化


[Quote=引用 2 楼 namewchwch 的回复:]

从前往后推 :
注意为了放入更多的球 (1)第i个球能放的盒子号码最多为i,不能放入第i+1及以后的盒子
(2)当第一个球不选择放入时候,相当于后面球的编号都减1,再参照(1)

f(V,m-1) = max { f(V - vi,m-1)+1,f(V,m-1)}

f(V,m-1):指的是当前装载空间为V 剩余装载盒子为m-1 ……
[/Quote]
fanster28_ 2010-08-04
  • 打赏
  • 举报
回复
你的状态转移方程没看懂,能详细一些么

[Quote=引用 2 楼 namewchwch 的回复:]

从前往后推 :
注意为了放入更多的球 (1)第i个球能放的盒子号码最多为i,不能放入第i+1及以后的盒子
(2)当第一个球不选择放入时候,相当于后面球的编号都减1,再参照(1)

f(V,m-1) = max { f(V - vi,m-1)+1,f(V,m-1)}

f(V,m-1):指的是当前装载空间为V 剩余装载盒子为m-1 ……
[/Quote]
绿色夹克衫 2010-08-04
  • 打赏
  • 举报
回复
刚注意到这个条件“且不能把球u放到盒子 p, 球 v 放到盒子 q ,当 u > v 且 p< q”,应该是四角不等式吧!
绿色夹克衫 2010-08-04
  • 打赏
  • 举报
回复
是不是二分+贪心呀?
没仔细想,检测m个盒子能否放下n个给定的球,用贪心可以么?
namewchwch 2010-08-04
  • 打赏
  • 举报
回复
从前往后推 :
注意为了放入更多的球 (1)第i个球能放的盒子号码最多为i,不能放入第i+1及以后的盒子
(2)当第一个球不选择放入时候,相当于后面球的编号都减1,再参照(1)

f(V,m-1) = max { f(V - vi,m-1)+1,f(V,m-1)}

f(V,m-1):指的是当前装载空间为V 剩余装载盒子为m-1 的状态下 可装的最大球数。
f(V,m-1) = max { f(V - vi,m-1)+1,f(V,m-1)}

f(V - vi,m-1) 指当前的球i可以装载下 并且选择装载球i 后的可装载最大球数
f(V,m-1) 指 当前球i 不被装载的最大球数。
michael122 2010-08-04
  • 打赏
  • 举报
回复
只能想到大概m*n^2的
估计一样超时

33,027

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧