一个难题

wangfengLLD 2007-12-06 05:14:33
一个长方形由9个正方形组成,且每个正方形的边长各不相同,已知有两个正方形的边长为12和21,
求长方形的面积?

请各位大侠帮帮忙,帮忙算算
我想用编程的方法做,但水平太低,编不出来。
...全文
558 40 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
40 条回复
切换为时间正序
请发表友善的回复…
发表回复
mu_yang 2007-12-13
  • 打赏
  • 举报
回复

谢谢flyingscv
到目前为止
你的结果是最好的
flyingscv 2007-12-12
  • 打赏
  • 举报
回复
是的

我重写了一个完备些的代码,并做了些优化
http://blog.csdn.net/flyingscv/archive/2007/12/12/1932191.aspx
mu_yang 2007-12-12
  • 打赏
  • 举报
回复
37楼的代码是在
1.指定长方形(长宽比)
2.按照指定阶数(不同正方形个数)
条件下的求解代码
对吗?
flyingscv 2007-12-10
  • 打赏
  • 举报
回复
先穷举出可能的正方形组合1 ,然后检测能不能拼成指定长方形2
程序用递归实现

1可能的组合:各正方形面积和与某个长方形面积相等,进行第一轮筛选

2就像用计算机玩只有大小不一的正方形的俄罗斯方块一样,搜索有没有解
WeinJones 2007-12-10
  • 打赏
  • 举报
回复
不好意思,看来我是写不出来了。

最近拿到了一个软件的核心代码。几百万行,正努力攻坚中.......

大家继续加油啊~
flyingscv 2007-12-10
  • 打赏
  • 举报
回复

#include <stdio.h>
#include <math.h>
#include <time.h>
#include <assert.h>

const MAXWIDTH = 120; //最大宽度
const MAXBASE = 3; //最小正方形最大尺寸
const RANK = 9; //阶数
const MARGIN = 10; //长宽最大差值(0表示正方形)

int square[MAXWIDTH]; //NUM个数的平方,优化效果微小
int result[RANK]; //可能的排列结果【0, rank-1】,从小到大

int width, height; //宽、高
int count = 0; //穷举记数

int flag[RANK]; //代表被使用的顺序号(索引);值[0,rank-1],rank表示未使用,>rank做标记用于输出结果,例:flag[RANK-1]=0,表示最大的正方形放第一个
int high[MAXWIDTH]; //已被填放的高度表,比如9×10的长方形放置一个5×5,则数据为:[5 5 5 5 5 0 0 0 0 0]
//注意:这两个数组用于递归,每个递归使用退出后需要还原原值

void perfectrect();
void check();
void search(int n, int index, int sum); //枚举正方形组合
bool searchrect(int n, int left); //判断能否填充

int main(int argc, char * argv[])
{
int i;

//预处理
for(i=1; i<=MAXWIDTH; i++)
{
square[i] = i * i;
}
perfectrect();

printf("Complete!\n");

return 0;
}

void perfectrect()
{
int sum;
int i;
static count2 = count;
time_t t;
time_t t2 = 0;

for(width=20; width<MAXWIDTH; width++)
{
for(height=width; height<=width+MARGIN; height++)
{
sum = height*width;
for(i=1; i<=MAXBASE; i++)
{
result[0] = i;
search(i+1,1, sum-square[i]);
}
}

t = clock();
printf("%d %10d %10d %10d %10d\n", width, count, t, count-count2, t-t2);
count2 = count;
t2 = t;
}
}


/* 穷举所有可能组合,放入result[RANK],并调用check()检查
n: 当前数最小值
index: 当前数索引[0, RANK-1]
sum: 后几位数累加和(含当前数)
*/
void search(int n, int index, int sum)
{
int i;

for(i=n;sum >=square[i]*(RANK-index); i++)
{
if(index == RANK-1 )
{
if(sum == square[i])
{
result[index] = i;
check();
break;
}
}
else
{
result[index] = i;
search(i+1, index+1, sum-square[i]);
}
}
}


//判断能否拼成指定长方形
void check()
{
count++;

int i, tmp;

for(i=0; i<RANK-1; i++)
flag[i] = RANK; //未使用

//第一个放置最大的
flag[RANK-1] = 0;
tmp = result[RANK-1];
for(i=0; i<tmp; i++)
high[i] = tmp;
// for(i=tmp; i<width; i++) //如果对第一行优化,则不需要这个
// high[i] = 0;

//放置第二个正方形,递归搜索
searchrect(1, tmp);
}


/* 穷举能放置的正方形,返回: true 能放,false 不能
n: 第n+1个正方形
left: 第一行时存放其起点,否则为0
*/
bool searchrect(int n, int left)
{
int i, j;
int pos, w, h; //最低处起始位置,高度,宽度
int tmp;


//对第一行优化处理
if(left != 0)
{
for(i=RANK-2; i>=0; i--) //从大到小放置([RANK-1]已被使用)
{
if(flag[i] < n)//是否已使用
continue;

if(result[i] > width-left) //放不下,下一个
continue;

flag[i] = n;
tmp = result[i];
for(j=0; j<tmp; j++)
high[j+left] = tmp;

if(tmp == width-left) //相等,搜索第二行
{
if(searchrect(n+1, 0)) //成功
{
flag[i] = RANK; //恢复标记
return true;
}
}
else //继续第一行
{
if(searchrect(n+1, left+tmp)) //成功
{
flag[i] = RANK; //恢复标记
return true;
}
}
flag[i] = RANK; //恢复标记
}

return false;
//assert(!"第一行排列出错");
}//是否第一行


//非第一行
//获取插入位置和大小
h = height+1;
bool exist = false;
for(i=0; i<width; i++)
{
if(exist && high[i] == h)
{
w++;
}
else if(high[i] < h)
{
h = high[i];
pos = i;
w = 1;
exist = true;
}
else
{
exist = false;
}
}

//遍历
for(i=RANK-2; i>=0; i--) //从大到小放置([RANK-1]已被使用)
{
if(flag[i] < n)//是否已使用
continue;

if(n == RANK-1) //完美长方形
{
if(w == result[i] && height == h+result[i])
{
for(j=0; j<RANK-1; j++)
{
for(int k=0; k<RANK; k++)
if(flag[k]==j)
printf("%d, ", result[k]);
}
printf("%d\n", result[i]);
return true;
}
else
continue;
}

if(w < result[i]) //放不下,下一个
continue;

tmp = result[i];
if(height < h+tmp) //高越界
continue;

flag[i] = n;

for(j=0; j<tmp; j++)
high[j+pos] += tmp ;

if(searchrect(n+1, 0)) //成功
{
flag[i] = RANK; //恢复标记
for(j=0; j<tmp; j++)
high[j+pos] -= tmp ;
return true;
}
else //不成功,恢复标记后转下一个
{
flag[i] = RANK; //恢复标记,好像多余
for(j=0; j<tmp; j++)
high[j+pos] -= tmp ;
}
}//逐个判断

return false;
}

hkk333 2007-12-09
  • 打赏
  • 举报
回复
台湾两个初3学生闲的没事搞这种研究?...
有点感慨.

感觉国内的初中生很多是让作业压的透不过气来,还能产生额外的兴趣那实在是罕见了

教育问题嘛,实在...
ltc_mouse 2007-12-09
  • 打赏
  • 举报
回复
楼上的找到解法了?能简单介绍下穷举时用的判断条件吗,呵呵
flyingscv 2007-12-09
  • 打赏
  • 举报
回复
9阶

18 14
4 10
15 7 1 9
8

0.3秒

10阶

30 25
3 8 17
27 11 2
13 15

290秒

阶数越高越慢
纯暴力穷举那个21阶的正方形的不大现实
需要优化
ltc_mouse 2007-12-09
  • 打赏
  • 举报
回复
mu_yang,没有结果啊,我加了些限定条件,依旧无法找到正确的解:
9个正方形的边长按递增顺序为a[1]...a[9]
(1)假设已知最大正方形边长为a[9]=N=18(这个限定似乎可以接受,因为可调整)
(2)因为已知4,7,和a[9],需要求剩下6个边长,穷举的方案数C(N-3,6)
(3)判断某种方案是否符合一系列必要条件(现在没找到适当的):
1. 面积Sum(a[i]*a[i])可分解成整数乘积 A * B (B>=A)
2. B和A分别满足 B>=a[9]+a[8], A>=a[8]+a[7];

其实判断条件2都无法证明是必要的,我甚至根据结果直接假定 B==a[9]+a[8], A==a[9]+a[7](这个假定,对于9阶的一种形式就不成立),满足的依然有29个;感觉需要找到能判断“缝隙”的条件
main90 2007-12-08
  • 打赏
  • 举报
回复
令最小的正方形边长是1,n>4,可画出如下图形(如果比较散乱,请拷贝到VC2005中查看)。如果x矩形是正方形的话,则2n+1=15,n=7。n取其余值,x则为一长方形,不满足题意。

/*

┏━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━┓
┃ ┃ ┃ ┃
┃ ┃ ┃ ┃
┃ X 2n+1┃ ┃ ┃
┃ ┃ ┃ ┃
┃ ┃ n+1 ┃ n+2 ┃
┃ ┃ ┃ ┃
┃ ┃ ┃ ┃
┃ ┣━━━━━━┳┫ ┃
┃ ┃ ┣┻━━━━━━━━┫
┃ ┃ ┃ ┃
┃ ┃ n ┃ ┃
┃ ┃ ┃ ┃
┃ 15 ┃ ┃ ┃
┣━━━━━━━━━━━━━┻━━┳━━━┫ n+3 ┃
┃ ┃ ┃ ┃
┃ ┃ 4 ┃ ┃
┃ ┃ ┃ ┃
┃ ┣━━━┻━━━━━━━━━┫
┃ ┃ ┃
┃ ┃ ┃
┃ ┃ ┃
┃ ┃ ┃
┃ n+11 ┃ ┃
┃ ┃ n+7 ┃
┃ ┃ ┃
┃ ┃ ┃
┃ ┃ ┃
┃ ┃ ┃
┃ ┃ ┃
┃ ┃ ┃
┃ ┃ ┃
┗━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┛

*/
mu_yang 2007-12-08
  • 打赏
  • 举报
回复
呵呵
目前WeinJones和我都还没什么好办法
ltc_mouse ,看你的了
ltc_mouse 2007-12-08
  • 打赏
  • 举报
回复
根据mu_yang的提示,查了下“完美长方形”,看到了,真可以称为完美啊,^_^
不过,没找到理论性的东西;想用穷举,但不知道怎么建立相应的模型来判断啊
WeinJones 2007-12-08
  • 打赏
  • 举报
回复
汗,写错了。

应该是长江后浪的后浪的后浪推它前浪的前浪的前浪。

虽然马上退休,但在没退休之前作为程序员还是应该严谨的!
WeinJones 2007-12-08
  • 打赏
  • 举报
回复
我试试写一个。

我也没想出答案。

看来长江后浪推前浪,我考虑退休。
昊叔 2007-12-07
  • 打赏
  • 举报
回复
,应该能拼出来
hai040 2007-12-07
  • 打赏
  • 举报
回复
同意ls,应该拼不出来
lxbxl_17 2007-12-07
  • 打赏
  • 举报
回复
楼主被耍了。
边长不同的正方形是不可能拼出矩形的。一定要2个边长相同才行。
wa_ning1982 2007-12-07
  • 打赏
  • 举报
回复
同意楼上的如果,每个正方形的边长都不相等,那么肯定会留下缝隙
flyingscv 2007-12-07
  • 打赏
  • 举报
回复
如果各正方形边长不等

怎么拼都会留下缝隙
加载更多回复(20)

65,186

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

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