Avatar billede jaweni Nybegynder
18. januar 2005 - 23:52 Der er 19 kommentarer og
1 løsning

Talkombinationer i tabel uden gengangere.

Jeg har en tabel med en talrække [1;20], hvoraf nogle
tal kan være "spærret" i forvejen (T[x] := 0), ellers
T[x] := 1; Årsagen til de "spærrede" tal kan være underordnet.

  I tabellen vil jeg checke et simuleret tal, fx. 26 op
imod tabellens "frie" tal og få samtlige talkombinationer,
som giver summen 26, vel at mærke UDEN gengangere, fx.:
(15 + 11) og (11 + 15), hvilket for mig er ens i denne
sammenhæng.

  Hvem har en smart løsning? Jeg venter med spænding!!
Avatar billede arne_v Ekspert
19. januar 2005 - 07:53 #1
Et bud:

program SumMatch;

{$APPTYPE CONSOLE}

uses
  SysUtils;

const
  maxvalid = 20;

type
  validlist = array [1..maxvalid] of integer;
  callback = procedure (a,b:integer);

procedure show(a,b : integer);

begin
  writeln(a,' ',b);
end;

procedure find(x : integer; valid : validlist; cb : callback);

var
  i,maxi,other : integer;

begin
  maxi := x div 2;
  for i := 1 to maxi do begin
    other := x - i;
    if other <= maxvalid then begin
      if (valid[i] = 1) and (valid[other] = 1) then begin
        cb(i, other);
      end;
    end;
  end;
end;

var
  i : integer;
  T : validlist;

begin
  for i := 1 to 20 do T[i] := 1;
  T[9] := 0;
  T[10] := 0;
  find(26, T, show);
end.
Avatar billede jaweni Nybegynder
24. januar 2005 - 10:31 #2
Hej arne v,

jeg har testet dit bud; men koden tager ikke
hensyn til at tallet 26, kan skrives på mange
andre måder, fx.: 10+16, 10+12+4, osv.

Koden skal kunne finde samtlige kombinationer
af fx. 26, forudsat at de enkelte tal er "frie".

Jeg prøver også selv på, at finde en løsning.

Mvh. jaweni
Avatar billede arne_v Ekspert
24. januar 2005 - 10:37 #3
Det fremgik ikke at det var validt med mere end 2 tal. Det komlicerer jo
tingene lidt.
Avatar billede jaweni Nybegynder
24. januar 2005 - 22:03 #4
Nej, jeg var nok ikke helt klar på det punkt.

For at gøre det hele lidt lettere, kan det simulerede
tal ligge i intervallet [1;12]. Maxvalid i [1;9], hvor
alle sat til 1;

Er det simulerede tal fx. 12, er der flg. 12 muligheder:
9 - 3, 9 - 2 - 1,
8 - 4, 8 - 3 - 1,
7 - 5, 7 - 4 - 1, 7 - 3 - 2
6 - 5 - 1, 6 - 4 - 2, 6 - 3 - 2 - 1
5 - 4 - 3, 5 - 4 - 2 - 1

Jeg håber ikke, at der en for stor mundfuld.
Avatar billede arne_v Ekspert
24. januar 2005 - 23:38 #5
program SumMatch;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  numlist = array of boolean;
  callback = procedure (valid:numlist);

procedure show(res:numlist);

var
  i : integer;

begin
  for i := 0 to high(res) do begin
    if res[i] then begin
      write(' ',(i+1));
    end;
  end;
  writeln;
end;

procedure find2(x : integer; valid : numlist; cb : callback; res : numlist; startix : integer);

var
  i,sum : integer;

begin
  sum := 0;
  for i := 0 to high(res) do begin
    if res[i] then begin
      sum := sum + (i+1);
    end;
  end;
  if sum = x then begin
    cb(res);
  end else if sum < x then begin
    for i := startix to high(res) do begin
      if valid[i] then begin
        res[i] := true;
        find2(x, valid, cb, res, i+1);
        res[i] := false;
      end;
    end;
  end;
end;

procedure find(x : integer; valid : numlist; cb : callback);

var
  i : integer;
  res : numlist;

begin
  setlength(res, high(valid) + 1);
  for i := 0 to high(res) do res[i] := false;
  find2(x, valid, cb, res, 0);
end;

var
  i : integer;
  t : numlist;

begin
  setlength(t, 9);
  for i := 0 to high(t) do t[i] := true;
  (* VIGTIGT : hvis 8 ikke må bruges er det t[7] som skal sættes til false *)
  find(12, t, show);
end.
Avatar billede arne_v Ekspert
24. januar 2005 - 23:38 #6
1 2 3 6
1 2 4 5
1 2 9
1 3 8
1 4 7
1 5 6
2 3 7
2 4 6
3 4 5
3 9
4 8
5 7
Avatar billede jaweni Nybegynder
26. januar 2005 - 16:39 #7
Jeg forstår ikke typedeklarationerne,
setlength og high(x).
Det virker ikke i Delphi 2, hvor jeg
vil lave et Windows-program med boxe,
knapper osv.

Kan du lave din kode om til fx. Borland
Pascal 7.0, som jeg kender bedst, for
jeg er en gammel DOSmer! Så får jeg det
nok tilpasset Delphi2.

Ellers kunne jeg sende min aktuelle kode,
hvor jeg ikke får kombinationer med mere
end 2 tal. Jeg mangler det rekursive kald,
som jeg ikke kan få programmeret.
Avatar billede arne_v Ekspert
26. januar 2005 - 16:43 #8
Jeg mener at jeg har TP7 liggende et sted derhjemme, så jeg kan sagtens
konvertere til det.

setlength og high har faktisk intet med selve algoritment at gøre - det er bare
for nemt at kunne håndtere variabelt antal
Avatar billede jaweni Nybegynder
26. januar 2005 - 16:56 #9
Hej igen,
hvis det er dig lige meget, så vil jeg hellere, at
du kigger på min kode. Dels har jeg nu arbejdet så
meget med den, at det svært at sætte mig ind i en
anden algoritme. Dels kan jeg bedre overse den række-
følge kombinationerne vises i.

Hvis OK, så sender jeg den senere.

PS: Er selve koden nok, eller skal du bruge alle filer
i projektet?
Avatar billede arne_v Ekspert
26. januar 2005 - 20:37 #10
Jeg kan godt kigge på din algoritme. Jeg kan dog i sagens
natur ikke garantere at den virker.

Bare koden er nok, så sætter jeg den selv ind i en kontekst.
Avatar billede jaweni Nybegynder
26. januar 2005 - 20:43 #11
Hermed koden, skulle det ikke virke, så vender jeg tilbage
Pft. jaweni

UNIT _sumtal;

INTERFACE

USES
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

TYPE
  Tabel = ARRAY[1..9] OF Byte;

  TForm1 = class(TForm)
    _options: TButton;
    _slut: TButton;
    LB1: TListBox;
    LB2: TListBox;
    Label1: TLabel;
    Label2: TLabel;
    PROCEDURE _optionsClick(Sender: TObject);
    PROCEDURE _slutClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  END;

VAR
  Form1: TForm1;

IMPLEMENTATION

{$R *.DFM}

PROCEDURE TForm1._optionsClick(Sender: TObject);
VAR
  T                  : Tabel;
  Txt, Txt2          : String;
  I, First, J, Max, X : Byte;

BEGIN
  FOR I := 1 TO 9 DO
    T[I] := 1;

  FOR I := 9 DOWNTO 1 DO BEGIN
    IF T[I] = 1 THEN BEGIN
      First := I; J := First;
      Max := 12;  Txt := '';
      WHILE (J <= Max) AND (T[J] = 1) DO BEGIN
        Txt := Txt + IntToStr(J) + ' - ';
        T[J] := 0;
        Dec(Max,J); J := Max;
        Txt2 := '';
        IF Max = 0 THEN BEGIN
          Delete(Txt,Length(Txt)-2,3); { Txt trimmes }
          LB2.Items.Add(Txt);

          FOR X := 1 TO 9 DO
            Txt2 := Txt2 + IntToStr(T[X]);

          LB1.Items.Add(Txt2);
        END;

      { IF ((Length(Txt) > 1) AND (T[First] = 0)) THEN BEGIN
            Max := 12; Text := '';
            T[First] := 1; J := First;  }

    { Er længden af [Txt] større end 1, så undersøges der for flere lavere
      talværdier med samme starttal, fx. 9,8 osv. Det er i hvert fald ideen;
      men programmet loop'er, så en rekursiv procedure a lá Find2 må være
      løsningen. }

      {  END;  }
      END; { WHILE .. }
    END; { IF .. }
  END; { FOR I .. }
END;

PROCEDURE TForm1._slutClick(Sender: TObject);
BEGIN
  Application.Terminate;
END;
END.
Avatar billede jaweni Nybegynder
26. januar 2005 - 20:53 #12
PS: Hvis ikke kombinationerne med mere end 3 tal fremkommer,
så er det ingen katastrofe; men helt OK, hvis det lader sig
gøre.
Avatar billede arne_v Ekspert
28. januar 2005 - 22:08 #13
pas

jeg kan ikke gennemskue den kode - og derfor heller ikke få den til at virke
Avatar billede jaweni Nybegynder
29. januar 2005 - 18:14 #14
OK, så må din kode laves til TP7 / Delphi2, hvis du har tid!

Har ikke forstået meningen med, at numlist først sættes
til TRUE alle 9 elementer, og i proceduren find, sættes
9 + 1 elementer til FALSE. Er det legalt i Delphi2?
Avatar billede arne_v Ekspert
29. januar 2005 - 20:19 #15
program SumMatch;

type
  numlist = array [0..8] of boolean;

procedure show(res:numlist);

var
  i : integer;

begin
  for i := 0 to 8 do begin
    if res[i] then begin
      write(' ',(i+1));
    end;
  end;
  writeln;
end;

procedure find2(x : integer; valid : numlist; res : numlist; startix : integer);

var
  i,sum : integer;

begin
  sum := 0;
  for i := 0 to 8 do begin
    if res[i] then begin
      sum := sum + (i+1);
    end;
  end;
  if sum = x then begin
    show(res);
  end else if sum < x then begin
    for i := startix to 8 do begin
      if valid[i] then begin
        res[i] := true;
        find2(x, valid, res, i+1);
        res[i] := false;
      end;
    end;
  end;
end;

procedure find(x : integer; valid : numlist);

var
  i : integer;
  res : numlist;

begin
  for i := 0 to 8 do res[i] := false;
  find2(x, valid, res, 0);
end;

var
  i : integer;
  t : numlist;

begin
  for i := 0 to 8 do t[i] := true;
  find(12, t);
end.
Avatar billede arne_v Ekspert
29. januar 2005 - 20:21 #16
vi har et array 0..8 altså 9 elemeenter

i find laver vi så et array med 9 elementer (8 + 1)
Avatar billede jaweni Nybegynder
08. februar 2005 - 04:29 #17
Hej arne, din kode var helt OK!
Avatar billede jaweni Nybegynder
08. februar 2005 - 04:32 #18
Hej igen, kan du ikke lige lave et svar
ellers kan jeg ikke give dig point.
Avatar billede arne_v Ekspert
08. februar 2005 - 07:20 #19
kommer her
Avatar billede arne_v Ekspert
25. februar 2005 - 22:12 #20
så mangler du bare at acceptere
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester