Matematické Fórum

Nevíte-li si rady s jakýmkoliv matematickým problémem, toto místo je pro vás jako dělané.

Nástěnka
22. 8. 2021 (L) Přecházíme zpět na doménu forum.matweb.cz!
04.11.2016 (Jel.) Čtete, prosím, před vložení dotazu, děkuji!
23.10.2013 (Jel.) Zkuste před zadáním dotazu použít některý z online-nástrojů, konzultovat použití můžete v sekci CAS.

Nejste přihlášen(a). Přihlásit

#1 23. 08. 2010 17:26

Luky10
Zelenáč
Příspěvky: 9
Reputace:   
 

Čokoláda

Dobrý den, chtěl bych váš poprosit o nějaký nápad (kód), pro tuto zákeřnou úlohu:

Je dána čokoláda o rozměrech 3xN čtverečků. Čokoláda má na některých čtvereččích umístěnu hrozinku. V zadání je dáno číslo N ("délka čokolády") a souřadnice [x;y] políček s hrozinkami. Určete počet způsobů, kolika můžeme rozdělit čokoládu na obdélníky 1x2, aby žádný z obdélníků neobsahoval hrozinku a tak byla čokoláda rozdělena na bezhrozinkové obdélníky 2x1 a čtverečky 1x1 s hrozinkou.


K zadání byl přiložen tento obrázek:
http://img178.imageshack.us/img178/7571/cokolada.png

A jeho řešení: Pro čokoládu vlevo je 0 možností a pro čokoládu vpravo 3 možnosti.

Zkoušel jsem vyřešit případy, kdyby čokoláda hrozinky neobsahovala, a to pro N=2 a N=3. Přišel jsem na to, že  pro případ N=2 jsou 3 možnosti a pro N=3 je 0 možností (je lichý počet políček, tak jedno vždy zbyde). Můj závěr pro čokoládu bez hrozinek je 3^(N/2) možností pro sudé N a 0 možností pro každé liché N. Bohužel ale nevím jak vytvořit algoritmus, který by to zjistil i pro čokoládu s hrozinkami :(.

Offline

 

#2 23. 08. 2010 17:50

Stýv
Vrchní cenzor
Příspěvky: 5692
Reputace:   215 
Web
 

Re: Čokoláda

zkusil bych prohledávání do hloubky. ale nevim, jestli je to zrovna efektivní

Offline

 

#3 23. 08. 2010 19:20 — Editoval RePRO (23. 08. 2010 19:22)

RePRO
Místo: Jihlava
Příspěvky: 363
Škola: AI VŠPJ (09-12, Bc.)
Pozice: programátor
Reputace:   11 
Web
 

Re: Čokoláda

To je hodně hustá úloha, ten algoritmus nebude jen tak jednoduchý. Pokud to dobře chápu, tak hrozinky nás vůbec neovlivňují, neboť jsou na poli 1x1. Takže nás pouze zajímá ta obdelníková část 2x1 bez hrozinek. Pokud najdeme čtvereček bez hrozinky a neexistuje k němu další (soused bez hrozinky), potom úloha nemá řešení, jinak má právě N řešení v daném cyklu.


Srdcem trochu-programátor, duší rádoby-matematik a povoláním analytik-vývojář.

Offline

 

#4 23. 08. 2010 21:45

check_drummer
Příspěvky: 4649
Reputace:   101 
 

Re: Čokoláda

Rozdělme čokoládu na "komponenty souvislosti" - každá komponenta je maximální souvislá plocha bez rozinky. Pak stačí vyšetřovat každou komponentu zvlášť a počet možných dělení je součin možných dělení u jednotlivých komponent.


"Máte úhel beta." "No to nemám."

Offline

 

#5 24. 08. 2010 18:40

Luky10
Zelenáč
Příspěvky: 9
Reputace:   
 

Re: Čokoláda

↑ check_drummer:
Nad tím jsem také přemýšlel - rozdělit to prostě na kusy ohraničené hrozinkou, ale to bohužel úlohu také neřeší - ten můj vzorec nefunguje, pokud to má nějaký divoký tvar, takže nevím, jak to udělat :((

Offline

 

#6 24. 08. 2010 22:10 — Editoval petrkovar (24. 08. 2010 22:19)

petrkovar
Veterán
Místo: Ostrava/Krmelín
Příspěvky: 1012
Pozice: VŠB - TU Ostrava
Reputace:   23 
Web
 

Re: Čokoláda

↑ check_drummer:A na každou komponentu souvislosti se můžeme dívat jako na bipartitní graf. Partity jsou indukovány "šachovnicovým" obarvením. Potom jde o to najít POČET úplných (někdy se jim říká perfektní) párování v bipartitním grafu (ne nutně pravidelném).
Řekl bych, že naprogramování algoritmu, který hledaný počet určí, bude jednodušší, než pokusit se sestavit obecný vzorec.

Offline

 

#7 26. 08. 2010 12:53

Luky10
Zelenáč
Příspěvky: 9
Reputace:   
 

Re: Čokoláda

Sice jsem si vyhledal, co to ten bipartitni graf je, ale bohuzel jsem te nepochopil. Byl bys prosim tak ochotny a napsal to treba v pseudokodu?

Offline

 

#8 26. 08. 2010 22:26

petrkovar
Veterán
Místo: Ostrava/Krmelín
Příspěvky: 1012
Pozice: VŠB - TU Ostrava
Reputace:   23 
Web
 

Re: Čokoláda

↑ Luky10:JPřiblížím tu grafovou formulaci.
Každému čtverečku bez hrozinky odpovídá vrchol grafu. Každý vrchol je spojen hranou s jiným vrcholem, pokud spolu na čokoládě sousedí hranou. Pokud by čokoláda byla barevná jako šachovnice, tak vždy sousedí černé čtverečky s bílými a naopak, nikdy černé s černými nebo bílé s bílými. Proto je graf bipartitní (jedna partita černé, druhá bílé čtverečky).
Pokud má některá komponenta lichý počet vrcholů, úloha nemá řešení. Pokud mají všechny komponenty sudý počet vrcholů, je potřeba pro každou komponentu najít (nejlépe rekurzívním algoritmem, nebo prohledáváním) počet různých párování a celkový počet je (jak už bylo řečeno) pak součinem počtu řešení pro jenotlivé komponenty.

Offline

 

#9 30. 08. 2010 10:06

Luky10
Zelenáč
Příspěvky: 9
Reputace:   
 

Re: Čokoláda

Ten graf bych měl uložit do pole nebo pomocí pointerů?

Načrtl jsem si situaci pro konkrétní čokoládu:
http://img837.imageshack.us/img837/3258/coko.jpg

Nevím sice, jak by se to dalo procházet rekurzivně, ale napadl mě tento způsob:

Code:

for i:=1 to pocet_vrcholu
      for j:=1 to pocet_vrcholu
              if (Sousedi_ij)=TRUE then 
                   vrchol[i]:=zabrany;
                   vrchol[j]:=zabrany;
             endif;
     endfor;
endfor;

if Vse_zabrane()=TRUE then Jedno_Reseni_mame else Nemame zadne;

tehnle kód bych spouštěl do té doby, dokud by to nenalezlo všechnya řešení, ale jak přijdu na to, že mám všechna ? :(

Offline

 

#10 01. 10. 2010 21:26

xxsawer
Příspěvky: 196
Reputace:   
 

Re: Čokoláda

↑ Luky10:

Dej vědět jestli si to už pořešil nebo ne...
Jinak přikláním se k tomu co říkal Stýv na začátku. Efektivita podle mě nemá smysl vůbec řešit, jestli nebudeš mít čokoládu 3x10000 tak výsledek dostaneš skoro okamžitě.

Offline

 

#11 09. 10. 2010 18:39

Luky10
Zelenáč
Příspěvky: 9
Reputace:   
 

Re: Čokoláda

Bohužel se mi to ještě nepovedlo vyřešit :(

Offline

 

#12 01. 11. 2010 23:53

Kondr
Veterán
Místo: Linz, Österreich
Příspěvky: 4246
Škola: FI MU 2013
Pozice: Vývojář, JKU
Reputace:   38 
 

Re: Čokoláda

Algoritmus ↑ petrkovar: je zřejmě korektní, ale jeho implementace vyžaduje přemýšlení. 

Proto navrhnu "brute force" alternativu: uvažme tabulku o sedmi sloupcích, sloupce odpovídají podmnožinám množiny {1,2,3} o 0,1 a 2 prvcích. Na i-tém řádku ve sloupci P je počet způsobů, jimiž lze rozdělit prvních i-1 řad čokolády tak, že v i-té řadě je přesahujícími obdélníky pokryta podmnožina P. Každý řádek spočteme rekurzivně z předchozího. Stačí nám pamatovat si dva poslední řádky.

Jistě jde o polynomiální algoritmus.


BRKOS - matematický korespondenční seminář pro střední školy

Offline

 

#13 04. 11. 2010 20:05

Lumikodlak
Místo: Praha
Příspěvky: 212
Pozice: Programator nebo tak neco :-)
Reputace:   19 
 

Re: Čokoláda

Zkusil jsem to naprogramovat rekurzivne po radcich, a povedlo se (sice ne v Pascalu, ale to je jedno). Slozitost je linearni (funguje v klidu pro stovky tisic radku). Jestli s tim stale potrebujes pohnout, tak dej vedet.

Offline

 

#14 04. 11. 2010 22:53

Kondr
Veterán
Místo: Linz, Österreich
Příspěvky: 4246
Škola: FI MU 2013
Pozice: Vývojář, JKU
Reputace:   38 
 

Re: Čokoláda

↑ Lumikodlak: S tou linearitou ... při běžném přístupu "do integeru se vleze vše", ano. Ale pokud by byly opravdu stovky tisíc řádků a na nich (téměř) žádné hrozinky, může mít výsledek stovky tisíc cifer, bylo by proto poctivější mluvit o kvadratické složitosti. Předpokládám, že ty jsi měl hrozinek hodně, pokud jsi nenarazil na omezení intu :)


BRKOS - matematický korespondenční seminář pro střední školy

Offline

 

#15 04. 11. 2010 23:30

Lumikodlak
Místo: Praha
Příspěvky: 212
Pozice: Programator nebo tak neco :-)
Reputace:   19 
 

Re: Čokoláda

↑ Kondr:
Mas pravdu, tohle jsem nebral v uvahu, int mi samozrejme pretekl :-) Kdyz by nebyl potreba presny vysledek, staci pouzit desetinna cisla a s tema by problem nebyl. Pravde jsi ale blize ty.

Offline

 

#16 07. 11. 2010 09:48

Luky10
Zelenáč
Příspěvky: 9
Reputace:   
 

Re: Čokoláda

↑ Lumikodlak:
Mohl bys ten kód prosíém někam umístit? (třeba sem na forum)
Sice už termín odevzdání vypršel, ale stejně mě velice zajímá, jak to vyřešit.
Dík

Offline

 

#17 07. 11. 2010 12:31

Lumikodlak
Místo: Praha
Příspěvky: 212
Pozice: Programator nebo tak neco :-)
Reputace:   19 
 

Re: Čokoláda

Tady to je, ale nevim, jestli je na prvni pohled jasne, jak to funguje. Muzu dat jeste nejake vysvetleni:

Code:

#include <stdio.h>

typedef struct{
  int PocetMoznosti;
  int VysledneRozvrzeni [3][3];
} Rozmisteni;

int Cokolada [1000][3] = {
  {0,0,0},
  {1,0,0},
  {0,0,1},
  {0,0,0},
  {1,0,0},
};

int CelkovyPocetMoznosti, IndexRozmisteni, IndexMoznosti, PocetRadek = 5;
int DocasnyRadek [3];
int MinuleMoznosti [2][2][2]  = {0,0,0,0,0,0,0,1};
int SoucasneMoznosti [2][2][2];

Rozmisteni Rozvrzeni [2][2][2] = {{{
  {3, 1,1,1 , 1,0,0 , 0,0,1 },                         //  0 0 0  
  {2, 1,1,0 , 0,0,0 }},{                               //  0 0 1  
  {1, 1,0,1 },                                         //  0 1 0  
  {1, 1,0,0 }}},{{                                     //  0 1 1  
  {2, 0,1,1 , 0,0,0 },                                 //  1 0 0  
  {1, 0,1,0 }},{                                       //  1 0 1  
  {1, 0,0,1 },                                         //  1 1 0  
  {1, 0,0,0 }                                          //  1 1 1  
  }}};

int main(){
  int CisloRadku;
  for (CisloRadku = 0; CisloRadku < PocetRadek; CisloRadku ++){
    memset (SoucasneMoznosti, 0, sizeof(SoucasneMoznosti));
    for (IndexRozmisteni = 0; IndexRozmisteni < 8; IndexRozmisteni ++){
      if (MinuleMoznosti [0][0][IndexRozmisteni]){
        for (IndexMoznosti = 0; IndexMoznosti < Rozvrzeni [0][0][IndexRozmisteni].PocetMoznosti; IndexMoznosti ++){
          memcpy (DocasnyRadek, Cokolada [CisloRadku], sizeof(DocasnyRadek));
          DocasnyRadek [0] += Rozvrzeni [0][0][IndexRozmisteni] . VysledneRozvrzeni [IndexMoznosti][0];
          DocasnyRadek [1] += Rozvrzeni [0][0][IndexRozmisteni] . VysledneRozvrzeni [IndexMoznosti][1];
          DocasnyRadek [2] += Rozvrzeni [0][0][IndexRozmisteni] . VysledneRozvrzeni [IndexMoznosti][2];
          if (DocasnyRadek [0] > 1 || DocasnyRadek [1] > 1 || DocasnyRadek [2] > 1) continue;
          SoucasneMoznosti [DocasnyRadek [0]] [DocasnyRadek [1]] [DocasnyRadek [2]] += MinuleMoznosti [0][0][IndexRozmisteni];
        }
      }
    }
    memcpy (MinuleMoznosti, SoucasneMoznosti, sizeof(MinuleMoznosti));
  }
  CelkovyPocetMoznosti = MinuleMoznosti[0][0][1] + MinuleMoznosti[1][0][0] + MinuleMoznosti[1][1][1];
  printf ("\nPocet moznosti je %ld", CelkovyPocetMoznosti);
}

Offline

 

#18 07. 11. 2010 16:30

Luky10
Zelenáč
Příspěvky: 9
Reputace:   
 

Re: Čokoláda

Díky moc ;)
Měl jsem potíž s funkcemi memset() a memcopy(), našel jsem si jejich princip a myslím, že jsem ho pochopil - daly by se ty funkce (popořadě) nahradit tímto?:

    for (i=0;i<=3;i++) { for (y=0;y<=3;y++) { for (x=0;x<=3;x++) { SoucasneMoznosti[i][y][x]=0;}}}
          for (i=1;i<=3;i++) {DocasnyRadek[i]=Cokolada [CisloRadku][i];}
     for (i=0;i<=3;i++) { for (y=0;y<=3;y++) { for (x=0;x<=3;x++) {MinuleMoznosti[i][y][x]=SoucasneMoznosti[i][y][x];}}}

Dále bych se chtěl zeptat, jestli by jsi mi nemohl vysvětlit jak generuješ obsah polí Rozvrzeni a MinuleMoznosti na základě pole Cokolada.
Děkuji předem za další odpovědi

Offline

 

#19 07. 11. 2010 18:46

Lumikodlak
Místo: Praha
Příspěvky: 212
Pozice: Programator nebo tak neco :-)
Reputace:   19 
 

Re: Čokoláda

Nahradit by to slo, akorat ty cykly trochu upravit, takze takhle:

for (i=0;i<2;i++) { for (y=0;y<2;y++) { for (x=0;x<2;x++) { SoucasneMoznosti[i][y][x]=0;}}}
          for (i=1;i<3;i++) {DocasnyRadek[i]=Cokolada [CisloRadku][i];}
     for (i=0;i<2;i++) { for (y=0;y<2;y++) { for (x=0;x<2;x++) {MinuleMoznosti[i][y][x]=SoucasneMoznosti[i][y][x];}}}


Rovrzeni a MinuleMoznosti negeneruju na zaklade Cokolady, ty jsou tam napevno, cili porad stejne pro jakoukoliv Cokoladu.

To pole Rozvrzeni udava, jak muzes rozmistit ty 2x1 obdelniky tak, abys zaplnil cely radek. Takze napriklad mas na radku prvni dva ctverecky volne, a treti obsazeny, takze [0][0][1] (okomentovano // 0 0 1). Kdyz chces tenhle radek zaplnit pomoci 2x1 obdelniku, tak bud tam das jeden horizontalne (takze na dalsim radku budes mit 0 0 0) anebo vlevo dva vertikalne (takze na dalsim budes mit 1 1 0). To {2, 1,1,0 , 0,0,0 } znamena jak muze vypadat ten dalsi radek (2 jako dve moznosti).

MinuleMoznosti [2][2][2]  = {0,0,0,0,0,0,0,1} to jsou jakoby pocatecni podminky - pro nulty radek.

Neni to moc jednoduche vysvetlit, tak jsem to asi moc dobre nevysvetlil :-)

Offline

 

#20 07. 11. 2010 21:34

Luky10
Zelenáč
Příspěvky: 9
Reputace:   
 

Re: Čokoláda

Někde asi bude chyba, tento kód:

Code:

#include <stdio.h>

typedef struct{
  int PocetMoznosti;
  int VysledneRozvrzeni [3][3];
} Rozmisteni;

int Cokolada [1000][3];

int CelkovyPocetMoznosti, IndexRozmisteni, IndexMoznosti, PocetRadek;
int DocasnyRadek [3];
int MinuleMoznosti [2][2][2]  = {0,0,0,0,0,0,0,1};
int SoucasneMoznosti [2][2][2];

Rozmisteni Rozvrzeni [2][2][2] = {{{
  {3, 1,1,1 , 1,0,0 , 0,0,1 },                         //  0 0 0
  {2, 1,1,0 , 0,0,0 }},{                               //  0 0 1
  {1, 1,0,1 },                                         //  0 1 0
  {1, 1,0,0 }}},{{                                     //  0 1 1
  {2, 0,1,1 , 0,0,0 },                                 //  1 0 0
  {1, 0,1,0 }},{                                       //  1 0 1
  {1, 0,0,1 },                                         //  1 1 0
  {1, 0,0,0 }                                          //  1 1 1
  }}};

int main(){
    int i,y,x;
PocetRadek=5;
for (i=0;i<PocetRadek;i++){for (y=0;y<=2;y++){ Cokolada[i][y]=0;}}
Cokolada[2][0]=1;
Cokolada[2][1]=1;
Cokolada[2][2]=1;



  int CisloRadku;
  for (CisloRadku = 0; CisloRadku < PocetRadek; CisloRadku ++){
for (i=0;i<2;i++) { for (y=0;y<2;y++) { for (x=0;x<2;x++) { SoucasneMoznosti[i][y][x]=0;}}}
    for (IndexRozmisteni = 0; IndexRozmisteni < 8; IndexRozmisteni ++){
      if (MinuleMoznosti [0][0][IndexRozmisteni]){
        for (IndexMoznosti = 0; IndexMoznosti < Rozvrzeni [0][0][IndexRozmisteni].PocetMoznosti; IndexMoznosti ++){
                   for (i=1;i<3;i++) {DocasnyRadek[i]=Cokolada [CisloRadku][i];}
          DocasnyRadek [0] += Rozvrzeni [0][0][IndexRozmisteni] . VysledneRozvrzeni [IndexMoznosti][0];
          DocasnyRadek [1] += Rozvrzeni [0][0][IndexRozmisteni] . VysledneRozvrzeni [IndexMoznosti][1];
          DocasnyRadek [2] += Rozvrzeni [0][0][IndexRozmisteni] . VysledneRozvrzeni [IndexMoznosti][2];
          if (DocasnyRadek [0] > 1 || DocasnyRadek [1] > 1 || DocasnyRadek [2] > 1) continue;
          SoucasneMoznosti [DocasnyRadek [0]] [DocasnyRadek [1]] [DocasnyRadek [2]] += MinuleMoznosti [0][0][IndexRozmisteni];
        }
      }
    }

      for (i=0;i<2;i++) { for (y=0;y<2;y++) { for (x=0;x<2;x++) {MinuleMoznosti[i][y][x]=SoucasneMoznosti[i][y][x];}}}
  }
  CelkovyPocetMoznosti = MinuleMoznosti[0][0][1] + MinuleMoznosti[1][0][0] + MinuleMoznosti[1][1][1];
  printf("Moznosti: %i",CelkovyPocetMoznosti);
}

Mi vypíše "Moznosti: 0" :(

Offline

 

#21 07. 11. 2010 21:44

Lumikodlak
Místo: Praha
Příspěvky: 212
Pozice: Programator nebo tak neco :-)
Reputace:   19 
 

Re: Čokoláda

Toho jsem si drive nevsimnul - nema byt
for (i=1;i<3;i++) {DocasnyRadek[i]=Cokolada [CisloRadku][i];}
ale
for (i=0;i<3;i++) {DocasnyRadek[i]=Cokolada [CisloRadku][i];}
snad takhle je to ok

Offline

 

Zápatí

Powered by PunBB
© Copyright 2002–2005 Rickard Andersson