一个有意思的问题---高效地截取管子的问题,算法.高分求解!

joners 2008-04-30 11:50:08
今天上午遇到了一个有意思的情况.
一家公司需要设计这样一款软件
具体的业务需求是这样的
这家公司是制作门窗的,材料是铝合金管 例如:6.3米一根
一根长管可能需要截取不同长度的小段.例如可能截取1米一段,2米一段,0.5米一段.具体如何截取和生产的产品大小规格有关.
希望编写一个软件,可以把材料利用律最大化.
软件主要有两类不同的参数
一类:需要输入截取几种不同长度的小段的长度.例如:1米,1.5米等.
二类:进料的长度.例如6.3米
目前小弟还没有拿出好的办法,各位老大有什么好的想法.
在线等待
...全文
1023 23 打赏 收藏 转发到动态 举报
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
bobniq 2009-05-07
  • 打赏
  • 举报
回复
down
Paradin 2009-05-05
  • 打赏
  • 举报
回复
up
Paradin 2009-05-05
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 tailzhou 的回复:]
感觉
brucesea
可口可乐的解法是可以的;

如果将每个小管子都进行编号,那么每一种裁法都可以对应到一个排列;
其中的每一个小管子要么跟上一小管子用同一管子,要么使用一个新的管子;
[/Quote]

那个是不是就是穷举啊?
Paradin 2009-05-05
  • 打赏
  • 举报
回复
感觉不是背包问题吧。。。是bin-packing

1)把这看成一个容积限制为L的0-1背包问题,先来填第一个背包;
2)所有物品是否已经全都放进去了?
如果是,算法结束;
如果没有,对剩下的物品再使用0-1背包的方法再填充一个容积为L的背包;
3)重复2

你看看我举这个例子有问题不:

包容积为10
10个物品体积为2 2 2 2 2 7 7 7 7 7

用背包的话:
第1个包: (2,2,2,2,2)
2 : (7)
3 : (7)
.. ...
6: (7)
一共6个包。
而实际上只要5个: (2,7) (2,7) (2,7) (2,7) (2,7)

不知道是不是我理解错了。。

我顶18楼
aayzaayz 2008-09-02
  • 打赏
  • 举报
回复
....
swbchangle 2008-06-12
  • 打赏
  • 举报
回复
明显是数学建模的题目

先确定切割模式:

模式i 截取a1长度的数量ri1,截取a2长度的数量ri2,截取a3长度的数量ri3,……,剩余长度(下脚料)ri

列出所有的模式。(规模较大的话得用程序实现)

设x1,……,xn为按照各种模式切割的钢管数

决策目标为Min x1+x2+……+xn

约束条件
根据要求列出方程组

为优化程序,可以加上x1>=x2>=……>=xn,因为各种模式的排列顺序无关

然后 用LINGO求解

junglesong 2008-06-12
  • 打赏
  • 举报
回复
mk
tailzhou 2008-05-02
  • 打赏
  • 举报
回复
这个问题直接用0-1背包应该有点问题;

比如大管子的长度为8米;
现在需要8个5米的,以及8个2米的;

如果用背包,那么前两根大管子就会被裁成8根2米的;
这样就需要10跟大管子;

但每根大管子都裁成5+2,只需要8根;
tailzhou 2008-05-02
  • 打赏
  • 举报
回复
感觉
brucesea
可口可乐的解法是可以的;

如果将每个小管子都进行编号,那么每一种裁法都可以对应到一个排列;
其中的每一个小管子要么跟上一小管子用同一管子,要么使用一个新的管子;
baobao2010 2008-05-02
  • 打赏
  • 举报
回复
mark
可口可乐 2008-05-02
  • 打赏
  • 举报
回复

原来的代码求最优解部分min搞错了,改一下。

代码含义:
pair<int, double> dp[100][100][100];

这儿假设有三种可能的截取长度,
dp[n1][n2][n3]用于保存对应于每种截取长度所需个数为n1,n2,n3时的最优解,
pair<int, double>中int用于保存材料个数,double用于保存当前剩余长度。

dp[n1][n2][n3]可以由dp[n1-1][n2][n3],dp[n1][n2-1][n3],dp[n1][n2][n3-1]中最优的一个获得,
参考代码。

可能存在的问题:
内存消耗。如果有k种可能的截取长度,每种最大需要的个数为Ni,
如果N1*N2*...*Nk内存可以接受的话,动态分配dp的大小,这儿的解法可能没什么问题。
如果内存过大,可以采用map,以(n1,n2,...,nk)作为索引。



double material = 6.3;
double size[3] = {0.5, 1, 2};
pair<int, double> dp[100][100][100];

pair<int, double> get(pair<int, double>& p, int id)
{
if (size[id] > p.second)
return (make_pair(p.first+1, material - size[id]));
return (make_pair(p.first, p.second - size[id]));
}

pair<int, double> minp(pair<int, double>& p1, pair<int, double>& p2)
{
if (p1.first < p2.first) return p1;
if (p1.first == p2.first)
{
if (p1.second > p2.second) return p1;
}
return p2;
}

pair<int, double> go(int n1, int n2, int n3)
{
if (dp[n1][n2][n3].first != -1) return dp[n1][n2][n3];

pair<int, double> p1, np1, p2, np2, p3, np3;
np1.first = np2.first = np3.first = INT_MAX;
if (n1 > 0)
{
p1 = go(n1-1, n2, n3);
np1 = get(p1, 0);
}
if (n2 > 0)
{
p2 = go(n1, n2-1, n3);
np2 = get(p2, 1);
}
if (n3 > 0)
{
p3 = go(n1, n2, n3-1);
np3 = get(p3, 2);
}

pair<int, double> min0 = minp(minp(np1, np2), np3);
dp[n1][n2][n3] = min0;

return min0;
}

void cal()
{
for (int i = 0; i < 100; i++)
for (int j = 0; j < 100; j++)
for (int k = 0; k < 100; k++)
dp[i][j][k] = make_pair(-1, 0);

dp[0][0][0].first = 0;
dp[0][0][0].second = 0;

go(10, 20, 30);

cout << go(10, 20, 30).first << endl;
}
joners 2008-05-01
  • 打赏
  • 举报
回复
up
rover___ 2008-05-01
  • 打赏
  • 举报
回复
6.3米分成1米,1.5米这2种的话,没什么好优化的。1米,1.5米的价格如何不明白的话,只能按照其尺寸定价。6.3米分成6个1米,4个1.5米,2个1.5米和3个1米,都是最优解。除非能给出不同尺寸材料的价格来,要不没法整体优化。
knowledge_Is_Life 2008-05-01
  • 打赏
  • 举报
回复
以后需再关注,现在先帮你顶一下
yatobiaf 2008-04-30
  • 打赏
  • 举报
回复
动态规划啊,典型的背包问题。
C1053710211 2008-04-30
  • 打赏
  • 举报
回复
动态规划,建立一个表示管子总长度的数组d,
对于d[i],如果能够截取出长度为i的管子,那么d[i]为1,否则为0;
状态转移方程
if d[i-l[j]]==1 ,d[i]=1,l[j]是可供选择的那些截取长度,0<j<n,
else d[i]=0 ,d数组中下标最大那个为1的i就是所求。
joners 2008-04-30
  • 打赏
  • 举报
回复
再补充说下:
原材料是成批购买的,例如可能买50根 6.3米的管子.
截取的小段也是很多可能需要截取20根1米的,20根1.5米的
可口可乐 2008-04-30
  • 打赏
  • 举报
回复
先贴个代码,没时间解释了,
也不知道对不对,回去再看看



double size[3] = {0.5, 1, 2};
pair<int, double> dp[100][100][100];
double material = 6.3;

pair<int, double> get(pair<int, double>& p, int id)
{
if (size[id] > p.second)
return (make_pair(p.first+1, material - size[id]));
return (make_pair(p.first, p.second - size[id]));
}

pair<int, double> go(int n1, int n2, int n3)
{
if (dp[n1][n2][n3].first != -1) return dp[n1][n2][n3];

pair<int, double> p1, np1, p2, np2, p3, np3;
np1.first = np2.first = np3.first = INT_MAX;
if (n1 > 0)
{
p1 = go(n1-1, n2, n3);
np1 = get(p1, 0);
}
if (n2 > 0)
{
p2 = go(n1, n2-1, n3);
np2 = get(p2, 1);
}
if (n3 > 0)
{
p3 = go(n1, n2, n3-1);
np3 = get(p3, 2);
}

pair<int, double> minp = min(min(np1, np2), np3);
dp[n1][n2][n3] = minp;

return minp;
}

void cal()
{
for (int i = 0; i < 100; i++)
for (int j = 0; j < 100; j++)
for (int k = 0; k < 100; k++)
dp[i][j][k] = make_pair(-1, 0);

dp[0][0][0].first = 0;
dp[0][0][0].second = 0;

go(10, 20, 30);

cout << dp[10][20][30].first << endl;
}
  • 打赏
  • 举报
回复
价格?这里面没有涉及到价格,或者可以认为所有物品的价格是和体积/重量成正比的,所以只考虑体积/重量一个因素就够了。

那个公式是用来说明问题的(用的管子越少越省料),但无法直接用来演算。因为具体用到多少根大管子是受小管子数量和长度影响的,不能直接套公式。举个例子来说:大管子长6.3米,现在需要截出3根长4米的小管子,如果直接看公式6.3*2>4+4+4,好像用两根就可以了,但实际上需要3根才能裁出来。

这个解答其实已经很清楚了,你的问题还是在于对0-1背包问题不了解。关于这方面的资料网上有很多,建议你先看看。

joners 2008-04-30
  • 打赏
  • 举报
回复
谢谢,dlyme:
经典的背包问题中,价格是不是一个干扰?如果把价格问题去掉?
令为了验证是不是最优方案,是否要把"m*L-n[1]*L[1]-n[2]*L[2]-…-n[k]*L[k]"公式代入演算啊?
还有很多问题不明确,希望能给出详细的解答.
加载更多回复(3)

33,008

社区成员

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

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