Languages :: Pascal :: Need faster solution |
|||
| By: StillUnAware |
Date: 07/05/2003 00:00:00 |
Points: 100 | Status: Answered Quality : Excellent |
|
I have decided to check is it possible to divide any rectangle to the squares, which are all of different sizes. As an example I got this one: Dimmension are: DimX := 33, DimY := 32. And the result is: it is possible to divide the rectangle to 9 squares, and their dimmensions are as follows : 9, 10, 14, 8, 1, 7, 4, 18, 15. My program already uses dinamic memory, but still works very slowly. My algorithm is the worst :), I know that, and maybe You can help me to optimize the code. I have no more ideas left. Thank You. Andrius. {====================== My program =============================} Program Rectangle_splitting_to_squares; { Search engine: ascending, } Uses Crt; { using dinamic memory } Type SquareLine = array [1..MaxInt div 2] of integer; rec = ^number; number = record num, Count :integer; back, next :rec; end; Var DimX, DimY :integer; SquareDim :SquareLine; HowMany :integer; ii :longint; jj, tmp :integer; Sheet :rec; StartAddress :pointer; Procedure InRec(var rcd :rec; nm, Counter :integer); Var rcdi :rec; Begin if rcd <> nil then While rcd^.next <> nil do rcd := rcd^.next; New(rcdi); rcdi^.next := nil; rcdi^.num := nm; rcdi^.Count := Counter; rcdi^.back := rcd; rcd^.next := rcdi; rcd := rcdi; end; Procedure Split( var Depth :integer; var SqDim :SquareLine; var rc :rec; m, n :integer; SA :pointer ); Var i, j, b, Width, z :integer; Start :pointer; Cancel :boolean; Begin Cancel := false; write( 'Depth: ', Depth:3, ' Û ' ); for i := 1 to Depth do begin write( SqDim, ' ' ); end; writeln(' '); gotoXY( 1, wherey ); rc := SA; Repeat if rc^.num = 0 then Begin Start := rc; Width := 1; while ( rc^.next^.num = 0 ) and ( rc <> nil ) do begin rc := rc^.next; inc( width ); end; b := 0; rc := Start; repeat b := b + m; until b > rc^.Count; b := b - rc^.Count; if b < width then width := b; b := n - rc^.Count div m; if b < width then width := b; Cancel := true; end; if rc = nil then Begin writeln( 'This rectangle was splitted into ' , Depth, ' squares' ); write( 'Depth: ', Depth, ' . Squares: '); for i := 1 to Depth do write( SqDim, ' ' ); writeln; halt; end; rc := rc^.next; until Cancel; for i := 1 to Width do Begin Cancel := false; for j := 1 to Depth do if ( SqDim[j] = i ) then Cancel := true; if not Cancel then Begin rc := Start; for b := 1 to i do Begin for j := 1 to i do begin rc^.num := i; rc := rc^.next; end; if b < i then for z := 1 to (m - i) do rc := rc^.next; end; rc := Start; inc( Depth ); SqDim[ Depth ] := i; Split( Depth, SqDim, rc, m, n, SA ); end; end; rc := SA; repeat if rc^.num = SqDim[ Depth ] then Break; rc := rc^.next; until rc = nil; for b := 1 to SqDim[Depth] do Begin for j := 1 to SqDim[Depth] do Begin rc^.num := 0; rc := rc^.next; end; for z := 1 to (m - SqDim[Depth]) do if rc <> nil then rc := rc^.next; end; SqDim[ Depth ] := 0; dec( Depth ); end; Begin Write ('Input dimensions for rectangle: '); Readln( DimX, DimY ); HowMany := 0; tmp := 0; for ii := 0 to DimX*DimY - 1 do InRec( Sheet, 0, ii ); While Sheet^.back <> nil do Sheet := Sheet^.back; StartAddress := Sheet; write('Depth: '); Split( HowMany, SquareDim, Sheet, DimX, DimY, StartAddress ); writeln; end. {================================== End of My program ============================} |
|||
| By: StillUnAware | Date: 07/05/2003 22:20:00 | Type : Comment |
|
| I think I should tell what my program does. 1) initializes the two direction list with 0, the number of varriables in memory is DimX*DimY (length and height of the rectangle), Sheet^.num saves the squares dimension which is graphicaly in the field (m*n), Sheet^.Count shows place of the element. 2) HowMany (Depth) counts how many squares is right now. 3) procedure Split recursively tries to put all rectangles in a row from left to rigth and from top to bottom. Maybe there is other algorithm to solve the problem. For example from what size of square to start the recursion. I have some ideas: squares of sizes 1 and 2 will never be near the "walls" of a rectangle. Also square can "touch" only two other squares with its one side... ( but this is prety hard to bring to life :) So in conclusion > I need your adwise ( better algo the most ). StillUnAware - Andrius |
|||
| By: VGR | Date: 07/05/2003 22:58:00 | Type : Comment |
|
| At least THAT's challenging :D |
|||
| By: StillUnAware | Date: 07/05/2003 23:56:00 | Type : Comment |
|
| I think so. Do You have any ideas? :) |
|||
| By: VGR | Date: 08/05/2003 00:50:00 | Type : Comment |
|
| yes. a lot. But I don't have a lot of time :/ perhaps later this evening. |
|||
| By: Okey | Date: 08/05/2003 00:57:00 | Type : Comment |
|
| First Idea : Your dynamic engine is good, but it is a Heap thing and so a little bit slower then direct DATA access! It seems nessecary, but nothing... I think your code is well enough to work?, and you should only cut your Routines to Screensize (25/50 Lines) Remember Pascal has been invented to make programming code more understandable like talking to someone; so don't be lazy and write expressions completely and you'll be able to read down your proggy and understand it in one ``Shoot´´! Do you know assembler? There are all possibilities hidden to make your proggy faster from optimizing Data up to optimizing Code! Appropos Style : Good style starts with readabillity of source, avoids spaghetti-code (Label & Goto) and avoids recursion as far as possible because it leads to many problems, futher ... How shall I explain you here what I learned my Lifetime? Try this hints and tell me what you want to avoid and why so that we can terll you howto. I'm sure People won't tell you all their secrets about good Programming technics! |
|||
| By: Okey | Date: 08/05/2003 01:02:00 | Type : Comment |
|
| Sorry I don't understand ! What if Your Rectangle is small like (2X1; 2x2 or 2X3) This would always lead to multiple Squares of same size, and in biger rectangles as well, too! |
|||
| By: VGR | Date: 08/05/2003 01:04:00 | Type : Comment |
|
| okey : there's no label nor goto in his code and I like recursion if it fits on a 64KB stack ;-) |
|||
| By: Okey | Date: 08/05/2003 19:41:00 | Type : Answer |
|
| Yeah if it fits, but thats realy not often and I didn't knew what to write to StillUnAware |
|||
| By: cuuu | Date: 08/05/2003 19:59:00 | Type : Comment |
|
| Hi, maybe you should use this approach - recursively generate lengths of squares that are worth checking - generate combinations of sqare side lengths that squared give DimX*DimY. In other words, generate combinations of 1..max(dimx,dimy), and check whether square sums of these combinations equals to dimx*dimy. if so, then there is a point to check these combinations. Generate those combinations recursively, say, dimx*dimy=100=total, then your procedure will look like this: Var res:array[1..max] of integer; {here we store values we have chosen so far} Procedure Generate(toSpare,lastChosen:longint; level:integer); Var i:longint; Begin if tospare=0 then CheckField(level) else begin if tospare>lastchosen then for i:=lastchosen+1 to toSpare do begin res[level]:=i; generate(toSpare-i,i,Succ(level)); End; End; End; You will launch it like this: Generate(100,0,1) 100 means - we have 100 cells to spare, 0 - last chosen element "was" 0 in order to start with 1 1 - start with level 1, we need this argument to know where to put numbers in the global array Unimplemented remains Procedure ChekckField - its job is to try to fit squares with sizes given in array's res[] 1 .. "level" elements. this procedure also will be most probably recursive. Such approach should be far better than full overlook; hope this helps, cuuu |
|||
| By: StillUnAware | Date: 08/05/2003 23:00:00 | Type : Comment |
|
| Thank you for your suggestions. I promise I'll try them all. I really liked the cuuu idea. It may speed up the program pretty well. All squares in a rectangle must be of different sizes (Okey) I heard that this problem is solved by using graph theory. But where to use it, I have no idea. Also I heard that for this exercise are used Kirchhoff's and Ohm's laws. This rectangle is like a conductor, and the squares in it divides the charge(load) and after that adds it again (for example starting from left top corner and ending at right bottom one). Also all this is a mitique for me. Sorry, I didn't write anything. I am a student, but don't have an InterNet at home, so I use the public computer. I'll try to be here every day. I am trully interested in this exercise now. Wish You luck. (If You're lucky, I'm lucky too ;) |
|||
| By: VGR | Date: 08/05/2003 23:20:00 | Type : Assist |
|
| some optimization remarks : Type SquareLine = array [1..MaxInt div 2] of integer; >> do you really need so much (static,non-dynamic) memory ? while ( rc^.next^.num = 0 ) and ( rc <> nil ) do >> turn shortcircuit boolean evaluation ON or this is supposed to fail as soon as rc is Nil (because then rc^ is undefined and the left operand can't be evaluated). Inverse also the two operands of the AND so that rc=Nil shortcircuits the boolean eval. That's {$B+} Cancel := false; for j := 1 to Depth do if ( SqDim[j] = i ) then Cancel := true; if not Cancel then >> this can be optimized this way, again with boolean eval optimized (shortcircuited) : NotCancel:=True; j:=1; While NotCancel AND j<=Depth Do Begin NotCancel:=SqDim[j]=i; Inc(j); End; if NotCancel Then b := 0; rc := Start; repeat b := b + m; until b > rc^.Count; >> optimized by stating : rc := Start; b := ((rc^.Count DIV m)+1)*m; rc := SA; repeat if rc^.num = SqDim[ Depth ] then Break; rc := rc^.next; until rc = nil; >> ugly. Should be (still with {$B+} ) : rc := SA; while (rc<>Nil)AND(rc^.num <> SqDim[ Depth ]) Do rc := rc^.next; for z := 1 to (m - SqDim[Depth]) do if rc <> nil then rc := rc^.next; >> this loop executes (m - SqDim[Depth]) times whatever the condition is ; it should be executed AT MOST that number of times, and at MOST until rc=Nil is encountered. Rewrite it with a while as above for b := 1 to SqDim[Depth] do Begin for j := 1 to SqDim[Depth] do Begin rc^.num := 0; rc := rc^.next; end; for z := 1 to (m - SqDim[Depth]) do if rc <> nil then rc := rc^.next; end; >> what's the point in those two outer loops ?!?? b is not used inside the loop j is not used either so basically you do SqDim[Depth]*SqDim[Depth] times the same thing on the same starting rc (potentially Nil as soon as second outer loop begins, BTW) and I'm not sure at all this is needed... I think this should be rethinkered and redesigned, IMHO |
|||
| By: StillUnAware | Date: 09/05/2003 02:48:00 | Type : Comment |
|
| Now I even know the name of this exercise. It is called Simple Squared Square, or Squared Rectangle. But now I think, I have to look for a graph theory all about this, it might be the only solution. Also I decided to divide not rectangle but square into square, it doesn't change a lot, but is even harder to solve. I looked over internet about this and found that the recent exercise is called Compound Perfect Square. There are some example solution, but not algorithms, maybe any of you know where to look for such a thing. |
|||
| By: cuuu | Date: 11/05/2003 04:37:00 | Type : Assist |
|
| Square problem cannot be harder to solve than rectangle problem, because square is just a special case of rectangle |
|||
| By: OpConsole | Date: 08/09/2003 13:02:00 | Type : Comment |
|
| StillUnAware: This old question needs to be finalized -- accept an answer, split points, or get a refund. |
|||
| By: StillUnAware | Date: 09/09/2003 20:50:00 | Type : Comment |
|
| Hi, if you still remember me. I decided to split points like this: VGR :40 cuuu :40 OKey :20 I hope that would be fear. BTW. The program itself is working, and I thank you all, but the main reason I've posted here was not the optimization of a routine, but the algorithm. And still thanks. StillUnAware |
|||
| By: VGR | Date: 09/09/2003 21:12:00 | Type : Comment |
|
| thanks |
|||
|
Do register to be able to answer |
|||
| Add This Article To: | |||
| |
|
|
|
| |
|
|
|








