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
Stránky: 1
ahoj, nevite nekdo jak rozlozit abecedu na tlacitka mobilniho telefonu tak aby se zachovalo poradi procemz vime cetnosti znaku...a mame to rozlozit tak aby se co nejmene mackalo...v abecede je 1 az n znaku
jestli mate nekdo napad jaky algoritmus by se mel tady uplatnit tak prosim napiste
dekuji moc
Offline
↑ hessyk:
To bude asi nejdříve chtít si sehnat četnost výskytu písmen v psaném textu viz.
Offline
Nejjednodušeji pomocí dynamického programování by se to dělalo takhle:
Pro všechny posloupnosti po sobě jdoucích písmen najdeme nejlepší rozmístění na k tlačítek, začneme s posloupnostmi délky 1 a jedním tlačítkem, pro daný počet tlačítek vždycky vypočítáme optimální rozmístění pro všechny posloupnosti.
Optimální rozmístění posloupnosti délky k s l mezerami získáme tak, že budeme postupně vkládat mezery mezi dvojice písmen a počítat optimální rozmístění pomocí už vypočítaných hodnot - z posloupnosti po novou mezeru a od nové mezery, přitom jedné dáme i mezer, druhé l-i-1.
Takhle dojdeme až k požadovanému počtu tlačítek a délce abecedy.
Je dobré si rozmyslet, že v tom postupu nemusíme zkoušet pro každou vybranou mezeru přidělovat mezery levé a pravé straně, stačí jít od začátku, za prvním písmenem buď mezera bude, nebo nebude.
Tím se dostáváme na něco jako O(t*n^3) s O(n^2) paměti, kde t je počet tlačítek, asi to půjde ještě vylepšit.
Doufám že to není moc zmatené, jestli si s dynamickým programováním moc nerozumíš, zkus nejdřív nějaké jednodušší příklady.
EDIT: Tak by to mělo být v O(t*n^2), kdyžtak si to zkusím ještě rozmyslet a poradím.
Offline
↑ hessyk:
Já možná jen zopakuju jinými slovy postup (případně popíšu obdobný), který popsal ↑ FailED::
Mějme k tlačítek a n písmen
Předvýpočet:
(četnost j-tého tlačítka budu značit w(j) )
Vytvoříme matici s políčky Cij - kde Cij bude cena, kterou nás bude stát vytvořit tlačítko, na kterém budou písmena i, i+1, ... j
Tedy Cij=1*w(i)+2*w(i+1)+3*w(i+2)...+(j-i+1)*w(j)
(když chci první písmeno z klávesy, musím ji zmáčknout jednou, když druhé, dvakrát, třetí třikrát... atd)
Hledání optimálního rozložení:
Budu vyplňovat další tabulku, a sice o rozměrech k x n - kde políčko Sij bude značit "optimální konfigurace i tlačítek taková, že i-té tlačítko končí na j-té klávese" (v políčku bude uložena vždy optimální cena)
První řádek (tedy políčka S1j pro j=1...n) lze zřejmě vyplnit for cyklem - je vždy jen jedna konfigurace, která se k tomu hodí, a ta odpovídá předvypočítaným číslům C1j pro j=1...n.
První políčko druhého řádku pro nás zřejmě nebudemít smysl (nemůžu použít dvě klávesy tak, aby druhá končila prvním písmenem).
Druhé políčko druhého řádku (S22) získám zřejmě tak, že vezmu S11 a přičtu k němu C22 (jinou možnost nemám - lze snadno rozmyslet)
Obecné políčko (tj. takové, kterým nezačíná řádek - rozuměj políčka tvaru Sii) Sij vyplním následovně:
někam si ukládej pomocnou proměnnou min; na začátku nechť je min=nekonečno (MaxInt apod)
(EDIT:chyba v řídící proměnné cyklu, opravena)
Pro m:=(i-1) do (j-1) dělej:
Vezmi S(i-1)m a přičti k němu C(m+1)j //// (oprava z m na m+1)
Je-li tato hodnota menší než min, pak min změn na tuto hodnotu
(konec cyklu)
Ulož min do Sij
(proč to funguje? při tvorbě optimální konfigurace takové, že i-té tlačítko končí j-tým písmenem, využijeme toho, že máme už spočítány optimální konfigurace pro rozložení (i-1) tlačítek tak, že (i-1)-té tlačítko končí písmenem (i-1), i, ... (j-1). K tomu máme spočteno, kolik nás bude ke každé této volbě stát "dodělat" potřebné tlačítko a minimum z těchto možností je optimálním řešením pro rozvržení, kde i-té tlačítko končí j-tým písmenem)
Takto postupně vyplníme celou tabulku. Protože nás zajímá optimum pro k tlačítek, kde k-té tlačítko končí n-tým písmenem, bude hledaná optimální cena rovna hodnotě Skn .
Pokud nás nezajímá jenom cena, ale i konkrétní rozložení, stačí jenom lehce upravit algoritmus - nebudu si pamatovat jenom dosavadní optimální cenu, ale zároveň s ní i políčko z předchozího řádku, kterého jsem pro výpočet tohoto optima využil. Pak stačí projít z Snk na políčko, které si pamatujeme u Snk, z toho políčka na políčko, které si pamatujeme tam atd až na nějaké políčko na prvním řádku. Tato políčka nám udávají, kterým písmenem bude která klávesa při optimálním rozložení končit.
Offline
ahoj, tak jsem si myslel ze jsem to pochopil ale nejak mi to nevychazi...mohl bys mi to prosim ukazat na nejakem jednoduchem priklade?treba ze mame a-f a cetnosti jsou 3,4,8,1,7,4 a mame to dat na 3 tlacitka...diky moc
Offline
↑ hessyk:
OK.
Doufejme tedy, že tam nemám nějakou numerickou chybu (počítám to jen tak v ruce, nemám to napsané ten program):
Tabulka Sij, i=1,2,3, j=1...6:
(indexy vždy značí, kolikátým písmenem končí předchozí klávesa; nekonečno je na pozicích, které pro nás nemají smysl (tj. situace, kdy na i tlačítek dám méně než i písmen, nebo naopak, kdy dám na i tlačítek tolik písmen, že se mi už zbylá tlačítka nepodaří nikdy nijak zaplnit - nezbudou mi písmena) )
Tedy v tomto případě je nejmenší možná cena na zmáčknutí tlačítek 36 a splňuje je rozložení:
a b | c d | e f
(Když už jsem to tu tak vypisoval - když si to člověk opravdu takto vypíše ručně, zjistí, že je možné algoritmus trochu optimalizovat, aby nedělal tolik různých porovnání - všimni si, že indexy u optimálních rozložení v jednom řádku nikdy neklesají; když si to zkusíš ručně spočítat, bude ti i jasné, proč)
EDIT: opraveno dle upozornění ↑ Lumikodlak:
Offline
Omlouvam se, ze do toho vstupuju, vsimnul jsem si, ze by melo podle me vyjit spis rozlozeni a b | c d | e f ktere ma vahu 36, ale nechci do toho rypat :-)
Offline
↑ Lumikodlak:
Děkuji, já to počítal na papíře, ale to koukám, že jsem hodně přestřelil : )) Asi bych si měl zopakovat sčítání.
/// už i vidím proč, prohodil jsem ceny dvou písmen (počítal jsem s cenami 3,4,8,7,1,4)
Jdu to opravit. Opraveno
Offline
↑ hessyk:
Tak já rozeberu třeba to poslední políčko, to je takové demonstrativní.
Hledáme optimální rozložení a cenu pro 3. tlačítko tak, aby končilo 6. písmenem (tedy vyplňujeme S36), celý předchozí řádek máme vyplněný (známe tedy optimální rozložení a ceny pro 2 tlačítka, ať už končí, kterýmkoli písmenem, které má smysl)
Když to udělám neoptimalizovaně, tak to bude probíhat následovně:
Min:=nekonečno;
Podívám se na S21... tam vidím nekonečno, takže vím, že je to nepřístupné rozložení, tak jdu dál
Podívám se na S22... tam je cena 7
- S22 je rozložení, kdy druhá klávesa končí na druhém písmeně, tedy musel bych dodělat tlačítko s písmeny 3-6, to by odpovídalo předvypočítané ceně C36, spočítejme to ručně:
C36=1*8+2*1+3*7+4*4=47 , celková cena je tedy 7+47=54.... to je menší než min (nekonečno), takže do min:=54; (pamatuji si prozatím, že jsem min získal použitím pozice 2 předchozího řádku)
Podívám se na S23 ... tam je cena 19
analogicky bych musel dodělat tlačítko o ceně C46 = 1*1+2*7+3*4=27, celková cena by tedy byla 27+19=46; to je menší než min a tedy min:=46 (pamatujeme si 3)
Podívám se na S24 ... cena 21
Dodělat bych musel tlačítko o ceně C56 = 1*7+2*4=15, celkově by to tedy bylo za 21+15=36, tedy min:=36 (pamatuju si 4)
Podívám se na S25 ... cena je 42, když budu ten program mít chytře napsanej, tak to ani nedopočítává, protože míň jak min to nakonec být nemůže (42+něco kladnýho > 36)
Konec cyklu a já svoje vypočítané min uložím do políčka S36. pokud tam mám nějakou strukturu, kam napsat, kolikátým písmenem končí předchozí tlačítko, uložím tam 4.
Takto by to vyplňovalo každé políčko. na konci by si to přečetlo hodnotu v S36 a tu vypsalo, pak by si to (do pole nebo někam) ukládalo "to druhé číslo" u políčka S36, poté podle něj skočilo na políčko S24 a tam si přečetlo "to druhé číslo" a to taky uložilo - tedy máš teď v poli nějakou posloupnost 4,2, a nakonec to podle ní vypíše děliče mezi ta písmena (tj jeden na 2., druhej na 4. pozici).
Offline
Ahoj,
dekuju ti za radu, je hezky ze se mi snazite pomoct. Chapu tuhletu cast jak jsi naposled vysvetloval a chapu i vytvoreni te tabulky "C" ale rozhodne nechapu jak tvoris tabulku "S". Nemohl bys mi sem napsat kusy kodu jak vyplnujes tabulku "S" nebo to nejak vysvetlit pro ten priklad co se tu resi. Zkousel jsem si to napsat ale ztratim se na tom ze nevim odkud nakonec nektere hodnoty beres a jak je mozny ze ti vznikne ta hodnota co je zrovna v tabulce.
Predem dekuju ze nejake rady a reakce.
Offline
↑ hessyk:
Toto bylo vytvoření jednoho políčka z tabulky S, konkrétně tedy posledního, kde předpokládám, že mám všechny vyšší řádky vyplněné. Ty jsem vyplňoval obdobně s předpokladem, že řádky před nimi mám již vyplněné. Takto jsem to dělal od druhého řádku, přičemž první řádek jsem vyplnil for cyklem (viz výše)
ještě to zkusme graficky:
F... vyplněno for cyklem
V... vyplněno dříve v programu algoritmem
X... právě vyplňovaný prvek
U... políčka, na základě nichž se X vypočítává
Zkrátka dodělávám i-tou klávesu. Tak se podívám, jak za co nejmenší cenu rozmístit (i-1) kláves a kolik mě bude stát dodělat to i-té tlačítko (to se liší podle toho, kde bude končit ta (i-1)-tá klávesa - proto postupně procházíme všechna možná písmena, na která může ta (i-1)-tá klávesa končit, no a nakonec vezmeme nejmenší celkovou sumu - tedy nejmenší z hodnot (cena pro i-1 tlačítek)+(cena dodělání i-tého tlačítka))
Offline
tak mam tu tuhle ulohu:
Na 50 klavesách (čínskeho) mobilního telefonu ma být rozloženo 2000 znaků (písmen) v pevně danem pořadí (podle abecedy). Písmeno, které je na nejake klávese uvedeno jako k-te,
se zapíše k stisky této klávesy. Přitom víte, jak často se které písmeno používa
(třeba jako pravděpodobnost nebo jako počet výskytů písmene v průmerné zpráve).
Program ma určit, na které klávese budou která písmena,
aby k napsáni průmerné zprávy byl potřeba nejmenší možný počet stisků.
Na vstupu váš program dostane:
počet kláves
počet znaků, které je nutno rozdelit
seznam četností jednotlivých znaků v průměrné zpravě.
Na výstup program vypíše vážený součet všech četností znaků.
Příklad:
3 //počet kláves
5 //počet znaků
1 //četnost prvního znaku
1 //četnost druhého znaku
1 //četnost třetího znaku
1 //četnost čtvrtého znaku
1 //četnost páteho znaku
Výstup:
Jedno z rešení je rozložit znaky nasledovně:
1 2 | 3 4 | 5
Pro první klávesu vypadá vážený součet takto:
1*1 + 2*1 = 3
Pro druhú:
1*1 + 2*1 = 3
Pro třetí:
1*1 = 1
Celkový výstup je tedy: 3+3+1=7
Program na výstup vypíše číslo: 7
napsal jsem tenhle program:
Program mobil;
var
klavesy,znaky,min,i,konec,j,vysledek:longint;
cetnost,mezery,pomoc:array[0..3000] of longint;
Procedure start;
var i:longint;
Begin
For i:=0 to znaky do
BEGIN
mezery[i]:=1;
pomoc[i]:=0;
END;
pomoc[1]:=0;
For i:=2 to znaky do
Begin
pomoc[i]:=cetnost[i]*2;
end;
End;
Function minimum:longint;
var i,min:longint;
Begin
min:=0;
For i:=1 to znaky do
If pomoc[i]>0 then
Begin
If min>1 then
Begin;
If pomoc[i]<pomoc[min] then min:=i;
End
else min:=i;
End;
minimum:=min;
end;
Procedure prepocet;
var i,stupen:longint;
begin
For i:=2 to znaky do
Begin
If mezery[i-1]=1 then
Begin
stupen:=mezery[i-2]+1;
pomoc[i]:=stupen*cetnost[i];
j:=i;
while mezery[j-1]<mezery[j] do
Begin
stupen:=stupen+1;
pomoc[i]:=pomoc[i]+stupen*cetnost[j+1];
j:=j+1;
end;
End;
End;
pomoc[1]:=0;
For i:=2 to znaky do
If mezery[i-1]>1 then pomoc[i]:=0;
End;
Procedure vypis(pole:array of integer);
var i:longint;
Begin
For i:=1 to znaky do
write(pole[i],' ');
writeln;
End;
Begin
readln(klavesy);
readln(znaky);
For i:=1 to znaky do
readln(cetnost[i]);
cetnost[znaky+1]:=0;
start;
While znaky-klavesy>0 do
Begin
min:=minimum;
If min>1 then mezery[min-1]:=mezery[min-2]+1 else mezery[min-1]:=2;
j:=min;
If min=znaky then konec:=0 else konec:=1;
While konec=1 do
Begin
If mezery[j]>1 then mezery[j]:=mezery[j-1]+1 else konec:=0;
if j=znaky then konec:=0;
j:=j+1;
End;
prepocet;
klavesy:=klavesy+1;
End;
vysledek:=0;
For i:=1 to znaky do
vysledek:=vysledek+cetnost[i]*mezery[i-1];
writeln(vysledek);
readln;
readln;
End.
porad mi to ale vypisuje spatnou odpoved muzete mi prosim nekdo tedy ukazat jak by mel vypadat spravny program nebo mi prepsat v tom mem programu chybu?nemuzu totiz na nic prijit...dekuju moc
Offline
↑ hessyk:
Tak jsem se k tomu taky dostal, paměť není moc omezená takže si můžu předpočítat ceny všech úseků a nechat si celou tabulku na dynamiku. Můžeš si rozmyslet jak by se to dalo upravit aby program používal jen lineárně mnoho paměti.
Tabulku vyplňuji tak, že postupně přidávám písmena, když přidám písmeno, zkusím všechny možné délky posledního úseku, rozdělení zbytku si přečtu z předchozího řádku (tam jsou ceny pro úseky s o jednu míň mezerami). - složitost je tedy v O(P^2*T) (Písmena, Tlačítka)
Můžeš se na to podívat, třeba pak najdeš chybu ve svém programu.
Offline
Stránky: 1