A programozó munkája a legkönnyebb /2

De tényleg, pl. ennél mi egyszerűbb: írjunk ki n tételt c hasábban, úgy, hogy az első c-1 hasáb tele legyen, az utolsóban legyen a maradék. Ehhez tényleg nem kell más, csak az alsó és felső egészrész, és/vagy a maradékos osztás ismerete.

Akkor most fussunk neki az n=18, c=7 vagy n=18, c=8 esetnek.

Hozzászólások

Legyen egymasra meroleges 7 piros vonal! De zold es atlatszo tintaval!

A strange game. The only winning move is not to play. How about a nice game of chess?

Nézd meg hogy az `ls -v` mit csinál. Nekem úgy tűnik hogy az is a kevesebb oszlopra szavaz.

Az alternatív specifikáció ötleted nekem nem tetszik, nem tűnik tipikus, jól ismert viselkedésnek.

Durván becsülve azt mondanám, hogy c>2 esetén c(c-1)/2 (c-1)(c-2)/2 [szerk: javítva] olyan szám van, amit nem lehet c oszlopban szépen elrendezni, ezek közül a legnagyobb az n=(c-1)^2 [szerk: meg még az n<c esetek, amit nem számoltam bele a fentibe]

Kipróbálva a lehetőségeket, a megkerülő megoldások közül az oszlopok számának csökkentése tűnik szebbnek; sőt, akár azzal is kezdhetjük, hogy ha az n kisebb a c néhányszorosánál, akkor szintén csökkentjük az oszlopok számát, hogy ne legyen túl széles a táblázat.

Jó feladat. Az a helyzet, hogy nincs mindig megoldása. Ugyanis amit valójában elvársz, az a következő: azt várod el, hogy az első maradékos osztás adjon nulla maradékot, vagy a második maradékos osztás adjon nemnulla maradékot. (Ezeket a maradékos osztásokat mindjárt leírom formálisan is.) És van olyan n és c, hogy egyik elvárás sem teljesül.

Tehát formálisan (az alábbiakban n, c, q, q2, r és r2 mind egész számok):

  1. Első körben azt a maradékos osztást nézed, hogy n = q * c + r, ahol adott n>0 a tételek száma, adott c>0 a teljes oszlopok száma, keresett q>=0 a hányados (sorok száma a teljes oszlopokban), és keresett c>r>=0 a maradék (az utolsó, nem teljes oszlopban lévő sorok száma -- maradék lévén ez kisebb, mint az osztó; ha már annyi sor szerepelne az utolsó, nem teljes oszlopban, mint ahány teljes oszlop van, akkor a hányados nőne meg, vagyis eggyel több sor lenne a teljes oszlopokban).

    Első körben azt várod el, hogy r=0 legyen; ekkor kapsz egy szép mátrixot, pontosan c oszloppal, és q sorral. (És ekkor rögtön adódik az is, hogy q pozitív, hiszen n = q * c.)

    Ha viszont r>0 adódik, akkor van egy nem teljes utolsó oszlopod is, amivel megszegted az "oszlopszám=c" elvárást, tehát át kell térnünk eggyel kisebb oszlopszámra ((c-1)-re). Itt rögtön látjuk azt is, hogy ebben az esetben c>=2 (tehát (c-1) még mindig pozitív lesz); ugyanis ha az eredeti osztó c=1 volt (összesen 1 oszlopot kértünk), akkor q=n (n sorunk lesz) és r=0 (nincs maradék -- nincs nem teljes oszlop) -- vagyis c=1 esetén nem jutottunk volna ide (ahol r>0).
     
  2. Második körben azt a maradékos osztást nézzük, hogy n = q2 * (c-1) + r2, ahol adott n>0 továbbra is a tételek száma, adott (c-1)>0 az oszlopok (eggyel csökkentett, de a fentiek szerint még mindig pozitív) száma, keresett q2>=0 hányados (a sorok száma a teljes oszlopokban), és keresett (c-1)>r2>=0 maradék (az utolsó, nem teljes oszlopban lévő sorok száma).

    Pontosabban (és ezen bukik a dolog): itt azt várjuk el, hogy r2>0 legyen. Ugyanis ha r2=0, akkor nincs betöltetlen oszlop, és kapunk egy szép mátrixot (c-1) oszloppal és q2 sorral -- ami viszont ismét megszegi az eredeti "oszlopszám=c" elvárást.

Vagyis a sejtésed az (más szóval: a specifikáció feltételezése az), hogy:

∀ n, c ∈ ℕ⁺: (∃ q ∈ ℕ⁺: n = q * c) ∨ (∃ q₂ ∈ ℕ, (c - 1) > r₂ ∈ ℕ⁺: n = q₂ * (c-1) + r₂)

Mivel ez egy olyan elsőrendű logikai állítás, amely univerzális kvantorral kezdődik, azért a cáfolatához elég egy ellenpéldát találni. Formálisan, a sejtés negáltja úgy néz ki, hogy először az egész elé kiragasztunk egy tagadást:

¬∀ n, c ∈ ℕ⁺: (∃ q ∈ ℕ⁺: n = q * c) ∨ (∃ q₂ ∈ ℕ, (c - 1) > r₂ ∈ ℕ⁺: n = q₂ * (c-1) + r₂)

Aztán a logikai "nem" operátort bevisszük az univerzális kvantoron belülre (amitől az egzisztenciális kvantorrá változik, a kvantált predikátum pedig negálódik):

n, c ∈ ℕ⁺: ¬((∃ q ∈ ℕ⁺: n = q * c) ∨ (∃ q₂ ∈ ℕ, (c - 1) > r₂ ∈ ℕ⁺: n = q₂ * (c-1) + r₂))

Azután a De Morgan azonossággal a negálást szétosztjuk a logikai "vagy"-on (amitől a "vagy" "és"-sé változik, az operandusai pedig negálódnak):

∃ n, c ∈ ℕ⁺: ¬(∃ q ∈ ℕ⁺: n = q * c) ¬(∃ q₂ ∈ ℕ, (c - 1) > r₂ ∈ ℕ⁺: n = q₂ * (c-1) + r₂)

Ismét a kvantoros játék:

∃ n, c ∈ ℕ⁺: ( q ∈ ℕ⁺: n q * c) ∧ ( q₂ ∈ ℕ, (c - 1) > r₂ ∈ ℕ⁺: n q₂ * (c-1) + r₂)

Ha ezt az állítást sikerül kielégíteni, akkor a sejtést megcáfoltuk.

Az általad adott n=18, c=7 számpár "létezik", és kielégíti a sejtés negáltját; vagyis cáfolja a sejtést:

(∀ q ∈ ℕ⁺: 18 ≠ q * 7) ∧ (∀ q₂ ∈ ℕ, 6 > r₂ ∈ ℕ⁺: 18 ≠ q₂ * 6 + r₂)

Ennek a konjunkciónak mindkét operandusa igaz, ugyanis:

  • a 18 nem osztható 7-tel (bármely pozitív egésszel szorozzuk a 7-et, nem lesz a szorzat 18), valamint
  • a 18-at 6-tal osztva 0 a maradék, ami pedig nem eleme az ℕ⁺ halmaznak (ha q₂ értéke 0, 1 vagy 2, akkor r₂ értéke rendre 18, 12, 6, amelyek egyike sem elégíti ki a 6>r₂ követelményt; ha q₂ értéke 3, akkor r₂=0, ami nem eleme az ℕ⁺ halmaznak; ha pedig q₂>3, akkor r₂ negatív, így nem eleme az ℕ⁺ halmaznak).

Összefoglalva: pontosan c oszloppal nem mindig megoldható a feladat; lehet, hogy (c-1) oszlopú mátrixot fogsz kapni. És ez az eset akkor áll fenn, ha c nem osztója n-nek, (c-1) viszont osztója n-nek.

> ez az eset akkor áll fenn, ha c nem osztója n-nek, (c-1) viszont osztója n-nek.

Először én is azt gondoltam, hogy ilyen egyszerű a szabály, de itt egy ellenpélda: legyen n=102, c=7, c-1=6. Ekkor r=intsup(102/7)=15, tehát az első 6 oszlopban 6*15 tétel lesz, az utolsóban a maradék: 102-6*15=102-90=12

c=7 esetén a legnagyobb problémás érték az n=36

PS: `intsup` jelöli itt a felső egészrészt, más néven`ceil`

itt egy ellenpélda: legyen n=102, c=7

Igazad van:

     0   1   2   3   4   5   6
 0 000 015 030 045 060 075 090
 1 001 016 031 046 061 076 091
 2 002 017 032 047 062 077 092
 3 003 018 033 048 063 078 093
 4 004 019 034 049 064 079 094
 5 005 020 035 050 065 080 095
 6 006 021 036 051 066 081 096
 7 007 022 037 052 067 082 097
 8 008 023 038 053 068 083 098
 9 009 024 039 054 069 084 099
10 010 025 040 055 070 085 100
11 011 026 041 056 071 086 101
12 012 027 042 057 072 087   -
13 013 028 043 058 073 088   -
14 014 029 044 059 074 089   -

Nézzük akkor negatív maradékkal:

  1. Először (szokásos maradékos osztás): n=q*c+r; 0<=r<c adódik.

    Ha r=0, akkor készen vagyunk (teljes téglalapot kaptunk).
     
  2. Egyébként n = q*c + r + (c - c) = (q+1)*c + (r - c) = (q+1)*c - (c - r) = (q+1)*(c-1) + ((q+1) - (c - r))

    Ez a megfogalmazás azt fejezi ki, hogy a sorok számát eggyel megnöveljük ((q+1)-re), melynek hatására az utolsó oszlopban a (q+1) elemből (c-r) elem hiányozni fog.

    Ez a módszer jól működik a példádon (q=14, q+1=15, r=4; az utolsó oszlop 15 eleméből c-r=7-4=3 elem hiányzik).

Ugyanakkor általában véve ezzel a módszerrel is baj van. A 2. lépésnél az utolsó oszlopban (q+1) elem fér el, és ebből (c-r) hiányzik -- az a baj, hogy a megmaradó elemek száma akár negatív is lehet, így az egész oszlop eltűnik.

Például legyen n=22, c=7. Ekkor q=3, r=1 (n=q*c+r; 22=3*7+1). A 7*3-as kezdeti táblázatba nem fér be 22 elem, 1 kimarad. A 2. lépés szerint legyen q+1=4 sor. Ennek hatására a táblázatba 7*4=28 elem fér be. Nekünk viszont csak 22 elemünk van, így az utolsó oszlopból 6 elem hiányzik. Igen ám, de az oszlopok magassága 4 elem, tehát az egész utolsó oszlop eltűnik -- nem lett meg a 7 oszlopunk. Az a baj, hogy a ((q+1) - (c - r)) különbség nem pozitív itt: (3+1) - (7 - 1) = 4-6 = (-2).

Rövidesen ilyesmi:

q = intsup(n/c)
r = n - q*(c-1)
gond akkor van, ha r<=0

Most tegyük fel, hogy n >= c, és n%c ≠ 0, kérdés, hogy r = n-intsup(n/c)*(c-1) mikor lesz nempozitív.

mondjuk n = Ac+B, ahol B=n%c>0, és A>0, ekkor intsup(n/c) = A+1,
r = n-(A+1)(c-1) = Ac + B - Ac - c + A +1

Vagyis r<=0 akkor teljesül, ha B+A+1 <= c, avagy B+A < c

Ilyen eset (c-1)(c-2)/2 van [ezt fentebb rosszul számoltam], a legnagyobb az A=c-2, B=1, n=(c-1)^2

Rövidesen ilyesmi:

q = intsup(n/c)
r = n - q*(c-1)
gond akkor van, ha r<=0

Most tegyük fel, hogy n >= c, és n%c ≠ 0, kérdés, hogy r = n-intsup(n/c)*(c-1) mikor lesz nempozitív.

mondjuk n = Ac+B, ahol B=n%c>0, és A>0, ekkor intsup(n/c) = A+1,
r = n-(A+1)(c-1) = Ac + B - Ac - c + A +1

Vagyis r<=0 akkor teljesül, ha B+A+1 <= c, avagy B+A < c

Ilyen eset (c-1)(c-2)/2 van [ezt fentebb rosszul számoltam], a legnagyobb az A=c-2, B=1, n=(c-1)^2

Végigszámoltam: ez jó!

Szövegesen, a módszer úgy dolgozik, hogy az osztásból származó oszloponkénti sorok számát felfelé kerekíti, és azt a feltételt keresi, amikor emiatt a felfelé kerekítés miatt az utolsó oszlop kiürül (eltűnik). Ez pedig ugyanaz az eset, mint amit én a negatív maradékos módszernél felírtam az utolsó oszlop eltűnéséhez (-> ha nem egzakt az osztás, akkor a sorok számát eggyel növeljük).

Azóta aludtam rá egyet, és most úgy gondolom, hogy amit pozitív ill. negatív maradékos módszerekként felírtam, azok együttesen véges lépésszámmal megoldják a feladatot (aminek lehet az az eredménye, hogy pontosan c oszloppal nem lehet a táblázatot elkészíteni, csak c-1 oszloppal):

  1. n = q * c + r; n>0; c>0; q>=0; c>r>=0
    ha r=0, akkor teljes a táblázat, kész vagyunk.
    Egyébként:
  2. megpróbáljuk a negatív maradékos módszert (sorok számának növelése 1-gyel):
    n = q*c + r + (c - c) = (q+1)*c + (r - c) = (q+1)*c - (c - r) = (q+1)*(c-1) + ((q+1) - (c - r))
    Ha itt a vastagon szedett ((q+1) - (c - r)) tag (az utolsó oszlop elemeinek száma) pozitív, akkor az utolsó oszlop nem üres, és kész vagyunk (pontosan c oszloppal).
    (Azt korábban nem írtam le, de (c-r) értékét a következőképpen becsülhetjük: mivel itt 0<r<c, azért c > (c-r) > 0. Tehát a legutolsó oszlopból minimum 1, legfeljebb (c-1) elem fog hiányozni.)
    Egyébként:
  3. megpróbáljuk a pozitív maradékos módszert (oszlopok számának csökkentése 1-gyel -- ennek az az értelme, hogy a sorok számának 1-gyel való növelésével eltűnt a c-edik oszlopunk, tehát most elindulunk abból az irányból, hogy 1-gyel kevesebb oszlopra lövünk eleve, és reménykedünk, hogy a maradék átfolyik a c-edik oszlopba):
    n = q2 * (c-1) + r2
    (Itt ugye tudjuk, hogy c>=2, mert c=1 esetén az 1. lépés végez, n=q és r=0 eredménnyel)
    q2>=0; (c-1)>r2>=0
    Ha itt r2 pozitív, akkor kész vagyunk (pontosan c oszloppal, ugyanis a c-1 oszlopos táblázatot kitöltöttük fullosra, a c-edik oszlopba pedig átcsorog r2>0 elem). Szerk. sajnos ez nem feltétlenül jó; r2 lehet nagyobb, mint q2, és akkor az utolsó oszlopot a maradékkal túltöltjük :(
    Egyébként:
  4. Készen vagyunk, teljes táblázattal, de csak (c-1) oszlopunk lett, és q2 sorral.

Az (n=102, c=7 --> q=14, r=4) példa arra, hogy a 2. lépés megoldja (az utolsó oszlop elemeinek száma (q+1) - (c - r) = 15-3 = 12), de a 3. és 4. lépések (amelyeket nem érünk el) rossz megoldást adnának (q2=17, r2=0).

Az (n=22, c=7 --> q=3, r=1) példa arra, hogy a 2. lépés nem oldja meg (a sorok számának 1-gyel növelése után az utolsó oszlopban (q+1) - (c - r) = 4-6 = (-2) elem lenne), de a 3. lépés megoldja (az oszlopok számát 1-gyel csökkentve q2=3 sor adódik c-1=6 oszlopban, és az utolsó (7.) oszlopba átcsorog r2=4 elem). Szerk. bocsánat, ez bugos -- az r2=4 elem nem fér el a 7. oszlopban, mivel csak q2=3 sorunk van!

Az (n=12, c=7 --> q=1, r=5) példa arra, hogy a 4. lépés oldja meg. A 2. lépés (negatív maradékos módszer, sorok számának növelése) q+1=2 sorral dolgozna, de a 7. oszlopba (q+1) - (c - r) = 2-2 = 0 elemet helyezne, így a 7. oszlop eltűnik. A 3. lépés (pozitív maradékos módszer, oszlopok számának csökkentése) c-1=6 oszloppal dolgozik, így q2=2 sorunk lesz, viszont r2=0 elem folyik át a 7. oszlopba, így az 7. oszlop itt is eltűnik, és azért eljutunk a 4. lépéshez -- csak 6 oszloppal lehet megoldani.

Később megpróbálok írni ide egy példa implementációt C-ben (már csak a magam kedvére is).

Ilyen eset (c-1)(c-2)/2 van [...], a legnagyobb az A=c-2, B=1, n=(c-1)^2

Továbbmorfondíroztam ezen -- ez a módszer nemcsak jó, hanem nagyszerű :) Ugyanis ha az első (n, c) inputra r<=0 jön ki (vagyis az utolsó oszlop kiürül), akkor tudsz elégséges követelményt megfogalmazni a c-re úgy, hogy második nekifutásra a módszer biztosan működjön: (√n)+1>c. Be tudsz állítani egy olyan új c-t, amire a módszer működni fog.

  • Ha n négyzetszám, akkor √n egész, így c := √n megfelel.
  • Ha n nem négyzetszám, akkor c := (⌊√n⌋+1) a legszorosabban értelmezett jó érték. (Lássuk azt, hogy ha n négyzetszám, akkor ez a számítás nem felel meg c-hez!)

A fentieket együttesen úgy is kifejezhetjük, hogy c :=⌈√n⌉.

Itt az az érdekes, hogy C-ben hogyan kódolod ezt le. Nekem az egyesített, felső egészrészes forma (c := ⌈√n⌉) nem tetszik, mert a c-r felső korlát van, tehát ha a ceil(sqrt(n))-ben mind az sqrt, mint a ceil felfelé kerekít, abból baj lehet. (Pl. n négyzetszám, de sqrt(n) egy olyan lebegőpontos értéket ad, ami a matematikai, egész értékű négyzetgyöknél epszilonnal nagyobb, amit aztán a ceil felkerekít a következő egészre.) Úgyhogy a szétválasztott esetek jobban tetszenek. Ott viszont:

Egyrészt hogyan tudjuk biztonsággal (egzaktul) megnézni, hogy n négyzetszám-e?

Másrészt sqrt()-hez a lebegőpontos környezetet úgy kell beállítani, hogy nulla (vagy mínusz végtelen) felé kerekítsen, attól függetlenül, hogy utána az eredményre a floor()-t alkalmaznánk. (Elvileg nem tartom lehetetlennek, hogy alapból felfelé kerekítő floating point env-nél az sqrt(n) egész számot adna olyan n-re, amely n=(k^2)-1 valamely egész k-ra. És akkor a floor(sqrt(n)) eggyel nagyobb értéket adna (nevesül floor(k)==k-t), mint a matematikai ⌊√n⌋ (ami k-1 lenne), vagyis a "c=floor(sqrt(n))+1" értékadás megszegné a c-re vonatkozó követelményt.)

Őszintén szólva nincs jobb ötletem, mint valahol feltúrni egy integer sqrt módszert (vagy "szegényemberes" megoldással megcsinálni lineáris vagy logaritmikus kereséssel), amely pont az ⌊√n⌋ értéket találja meg, utána pedig visszafelé ellenőrizni (egész aritmetikával), hogy ⌊√n⌋*⌊√n⌋ == n. Ha igen, akkor n négyzetszám (és c:=⌊√n⌋=√n), egyébként c nem négyzetszám (és c:=⌊√n⌋+1).

Ha emberi sorrendben írod ki (balról jobbra), akkor látszik, hogy miért nincs megoldás, mert több hasáb lesz hiányos: 

 1  2  3  4  5  6  7

 8  9 10 11 12 13 14

15 16 17

De akkor meg csak hat oszlopom van.

Ez nem igaz, a feladat sehol nem kötötte ki, hogy egy oszlopban minimum 1 tételnek kell lennie. Nem is kötheti ki, mert ha N az osztó akkor a maradék 0 és N-1 közé kell, hogy essen. Vagyis továbbra is 7 hasáb van, csak az utolsó hasáb, vagyis a maradék 0 tételt tartalmaz.

Oké, akkor mit kell érteni az alatt, hogy az első c-1 hasáb tele legyen? Én úgy értelmeztem, hogy a sorok száma maximális, vagyis r=intsub(n/(c-1)), ebben a példádban r=intsub(102/(7-1))=17, a maradék 102%(7-1)=0. Gondolom ha van intsup akkor van intsub is.

Ha csak annyit jelent, hogy egyenlő számú elem van bennük, akkor át lehet vinni valamennyi tételt az utolsó oszlopba, ha intsub(n/(c-1))-n%(c-1)>=c. Ha n<c akkor mindenképp lesznek üres oszlopok. A kettő között valamiből engedni kell, pl. n=36, c=7-nél mi lenne a jó megoldás?

n=36, c=7-nél mi lenne a jó megoldás

Ez egy jó példa. Ha oszloponként 5 elemmel dolgozunk, akkor nem férünk bele 7 oszlopba (5*7=35 < 36); ha pedig 6 elemmel, akkor az utolsó oszlop kiürül (6*6=36).

Ha megnézed NevemTeve hozzászólását itt, akkor az n=36, c=7 számpár pont az az eset, amikor az adott c-hez az n a legnagyobb olyan érték, aminél kiürül az utolsó oszlop (amikor a sorok számát felfelé kerekítjük): n=(c-1)^2; 36=(7-1)^2.

A megoldás szerintem az, hogy -- mivel n sokkal inkább rögzítettnek tűnik, mint c -- a c értékét kell csökkenteni; kevesebb oszlop kell. Tömören: c :=⌈√n⌉; de ezt C-ben egzaktul kódolni macerás (ld. a linkelt kommentemet).

Támadt egy új ötletem! :) (Bocsánat, ha valaki már írta a topicban.)

A táblázatban a helyeket (cellákat) töltsük fel sorfolytonosan, majd a megtalált cellákat az értékekkel töltsük fel oszlopfolytonosan!

Ennek az a szépsége, hogy tetszőleges (n>0, c>0) párra működik, és a kimenet jól néz ki, mert az összes oszlop majdnem ugyanolyan magas.

Ennek a "majdnem ugyanolyannak" itt a formális meghatározása (példa: n=27, c=5):

  0 1 2 3 4
0 X X X X X
1 X X X X X
2 X X X X X
3 X X X X X
4 X X X X X
5 X X

n = q * c + r (q >= 0; c > r >= 0)

A q megadja a teli sorok számát, az r pedig megadja, hogy az utolsó, nem teli sorban hány maradék elem van. Ha r=0, akkor egy szép teli téglalapot kaptunk.

Ha pedig r>0, akkor mindig az az elrendezés, a sorfolytonos cellaválasztás következtében, hogy a bal oldalon található egy r oszlopból és q+1 sorból álló "A" téglalap, a jobb oldalon pedig egy c-r oszlopból és q sorból álló "B" téglalap:

  0 1 2 3 4
0 A A B B B
1 A A B B B
2 A A B B B
3 A A B B B
4 A A B B B
5 A A

Aritmetikailag felírva a cellák számát az A és B téglalapokban:

r*(q+1) + (c-r)*q = r*q + r + c*q - r*q = c*q + r = n

Tehát jól számoltunk, valóban az n db cellát helyeztük el.

Ennek a felírásnak további szépsége az, hogy független attól, hogy r=0 vagy r>0. Ha ui. történetesen r=0, akkor az A téglalap szélessége egyszerűen 0 oszlop, a B téglalap szélessége pedig c-r = c-0 = c oszlop.

Akkor a cellákat elhelyeztük; hogyan töltsük fel azokat? Ugyanis printelni sorfolytonosan tudunk. Nem nehéz; minden sorban az induló érték (a 0. oszlop értéke) magának a sornak a száma. Ahogy jobbra haladunk az adott sorban, az értéket annyival kell megnövelnünk, mint az éppen elhagyandó oszlop magassága. Ha a jelenlegi oszlop száma (nullával kezdve a számozást) kisebb mint r, akkor ez a növekmény (vagyis az oszlop magassága) q+1, egyébként pedig q.

(Itt is látszik, hogy ha r=0, vagyis az osztás egzakt, akkor az "oszlop száma kisebb mint r" sosem teljesül, vagyis a növekmény mindig q.)

Itt a program:

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

#define CELL_WIDTH 3

static int
get_positive_long(long *val, const char *str)
{
  long tmp;
  char *end;

  errno = 0;
  tmp = strtol(str, &end, 0);
  if (end == str || *end != '\0' || errno != 0 || tmp <= 0) {
    (void)fprintf(stderr, "invalid value: \"%s\"\n", str);
    return -1;
  }
  *val = tmp;
  return 0;
}

int
main(int argc, char **argv)
{
  long num_val, num_col;
  ldiv_t qr;
  long row, col, val, i;

  if (argc != 3) {
    (void)fprintf(stderr, "usage: %s num_val num_col\n", argv[0]);
    return EXIT_FAILURE;
  }
  if (get_positive_long(&num_val, argv[1]) == -1 ||
      get_positive_long(&num_col, argv[2]) == -1) {
    return EXIT_FAILURE;
  }
  if (num_val < num_col) {
    (void)fprintf(stderr, "expected num_val(%ld) >= num_col(%ld)\n", num_val,
      num_col);
    return EXIT_FAILURE;
  }

  qr = ldiv(num_val, num_col);
  row = col = val = i = 0;
  for (;;) {
    (void)printf("%*ld", CELL_WIDTH + (col > 0), val);
    if (i == num_val - 1) {
      (void)printf("\n");
      break;
    }
    if (col < num_col - 1) {
      val += qr.quot + (col < qr.rem);
      ++col;
    } else {
      (void)printf("\n");
      val = ++row;
      col = 0;
    }
    ++i;
  }

  return EXIT_SUCCESS;
}

... Ja, tényleg, joco01 már említette a sorfolytonosságot.

#include <stdio.h>
#include <stdlib.h>

void draw(int num, int col, int row)
{
  int i, j, n;
  printf("    |");
  for (j = 0; j < col; ++j) printf("#%-3i|", j+1);
  printf("\n");
  for (i = 0; i < row; ++i)
  {
    printf("#%-3i|", i+1);
    for (j = 0, n = i; j < col; ++j, n += row)
      (n < num) ? printf("%4i|", n) : printf("   -|");
    printf("\n");
  }
}

void calc(int num, int inp_col, int *out_col, int *row)
{
  int m;
  *out_col = inp_col;
  m = num % inp_col;
  *row = num / inp_col;
  if (m == 0) return;
  (*row)++;
  if (inp_col - m < *row) return;
  *out_col = num / *row;
  if (num % *row > 0) (*out_col)++;
}

int main(int argc, char *argv[])
{
  int an,ac,r,c;
  an = atoi(argv[1]);
  ac = atoi(argv[2]);
  calc(an, ac, &c, &r);
  if (ac != c) printf("Nem oldhato meg %i oszlopban\n", ac);
  printf("Megoldhato %i oszlopban, %i sor\n", c, r);
  draw(an, c, r);
  return 0;
}