Zadání úloh ústředního kola (2. soutěžní den) 46. ročníku
Druhý soutěžní den - 25.4.1997
P-III-4
Program:
HRA.PAS
/
HRA.CPP
Hracím plánem je pás políček očíslovaných zleva doprava čísly 0,
1, 2, ... Na některých políčkách hracího plánu leží kamínek,
celkový počet kamínků k je mezi 1 a 4.
Pořadovým číslem kamínku
rozumíme počet kamínků, které leží na hracím plánu vlevo od něho.
První kamínek zleva má tedy pořadové číslo 0 a poslední k-1.
Každou situaci hry můžeme popsat počtem kamínků a čísly políček,
na nich jsou jednotlivé kamínky umístěny. Můžete předpokládat, že
žádný kamínek neleží na políčku s číslem větším než 2
31-1.
Koncovou situací hry je situace, v níž kamínky leží na políčkách
0, 1, ..., k-1.
Hru hrají dva hráči, kteří střídavě posouvají kamínky. V jednom
tahu je povoleno posunout jeden z kamínků o libovolný počet
políček při dodržení následujících pravidel:
- kamínky se posouvají směrem doleva
- na každém políčku je vždy nejvýše jeden kamínek
- počet kamínků, které leží vlevo od posouvaného kamínku, se
posunutím nezmění
V koncové situaci tedy není možné udělat žádný tah a hra končí.
Vyhrává ten hráč, který provedl poslední tah. Můžete
předpokládat, že hra nezačíná v koncové situaci.
Napište program (dále označovaný jako "hráč"), který bude hrát
tuto hru, a to vždy jako začínající (tj. první na tahu). Druhého
hráče bude zastupovat knihovna popsaná níže (dále označovaná jako
"protivník"), kterou použijete ve vašem programu. Vaším úkolem
je napsat program, který hraje co nejúspěšněji proti libovolnému
protivníkovi (tj. proti každé knihovně splňující uvedený popis).
Knihovny jsou uloženy v souborech HRA_C.LIBT
(pro C/C++), resp.
HRA_P.TPU
(pro Pascal).
Knihovna obsahuje následující prostředky:
/* C/C++ */
#ifdef __cplusplus
extern "C" {
#endif
#define MAXKAM 4
typedef long THraciPlan[MAXKAM];
void inicializuj (int* pocetKamienkov, THraciPlan hraciPlan);
void mojKrok (int kamienok, long dlzkaKroku);
void tvojKrok (int* kamienok, long* dlzkaKroku);
#ifdef __cplusplus
}
#endif
{Pascal}
interface
const MAXKAM = 4;
type THraciPlan = array[0..MAXKAM-1] of longint;
procedure inicializuj (var pocetKamienkov: integer;
var hraciPlan: THraciPlan);
procedure mojKrok (kamienok: integer; dlzkaKroku: longint);
procedure tvojKrok (var kamienok: integer;
var dlzkaKroku: longint);
Funkce inicializuj inicializuje hru a vrátí počáteční situaci
hry. V parametru pocetKamienkov vrátí počet kamínků na hracím
plánu a v poli hraciPlan vrátí pozice jednotlivých kamínků,
přičemž hraciPlan[i] je pozice kamínku s pořadovým číslem i, pro
i=0,1,...,pocetKamienkov-1 (hodnoty ostatních prvků pole nejsou
definovány).
Pomocí funkce mojKrok oznamujete protivníkovi svůj tah.
V parametru kamienok odevzdáte pořadové číslo posouvaného kamínku
a v parametru dlzkaKroku počet políček, o který posouváte zvolený
kamínek. Pomocí funkce tvojKrok získáte naopak soupeřův tah,
přičemž význam parametrů je stejný jako u funkce mojKrok.
Váš program na začátku výpočtu zavolá funkci inicializuj a potom
střídavě volá funkce mojKrok a tvojKrok, přičemž začíná voláním
funkce mojKrok. Můžete předpokládat, že protivník hraje korektně.
Jestliže hráč provede vítězný tah, tzn. tah po němž nastane
koncová situace, funkce mojKrok ukončí program. Jestliže naopak
protivník svým tahem zvítězí, funkce tvojKrok ukončí program.
Pokud váš program nedodrží popsané pořadí volání procedur nebo
pokud zadá nepovolený tah jako parametr funkce mojKrok, váš
program prohrává. Ukončení programu před koncem hry je zakázáno.
Poznámky
- Pro potřeby ladění máte k dispozici jednoho protivníka. Tento
protihráč načítá počáteční pozici ze souboru HRA.IN. Soubor
obsahuje počet kamínků a jejich pozice.
- Váš program může být testován i s jinými protivníky.
P-III-5
Program:
KURU.PAS
/
KURU.CPP
Vstup:
KURU.IN
Výstup:
KURU.OUT
Ve starověkém městě Kuru objevili archeologové zvláštní trezor.
Měl čtvery dveře. Dveře se musely otevřít ve správném pořadí,
neboť jinak celou místnost zalila voda. Na každých dveřích bylo
vytesáno nějaké zvíře. Na stěně archeologové rozluštili text
tohoto znění:
Jako první otevři dveře, na kterých je buď lev nebo orel.
Jako druhé otevři dveře, na kterých je buď had nebo škorpión.
Jako třetí otevři dveře, na kterých je buď orel nebo had.
Jako druhé otevři dveře, na kterých je buď lev nebo had.
Budeme-li předpokládat, že všechna tato tvrzení jsou pravdivá,
můžeme určit správné pořadí otvírání dveří. Z druhého a čtvrtého
tvrzení vyplývá, že jako druhé je třeba otevřít dveře s hadem.
Z třetího tvrzení a z faktu, že had je na druhých dveřích, plyne,
že orel je na třetích dveřích. Z prvního tvrzení a z faktu, že
orel je na třetích dveřích, vyplývá, že lev je na prvních
dveřích. Pro škorpióna zůstaly čtvrté dveře.
Napište co nejefektivnější program, který bude řešit takovýto typ
hlavolamů. Je dán počet dveří n (1 <= n <= 1000). Na každých dveřích
je vytesané jiné zvíře, přičemž tato zvířata označíme čísly od
1 do n. Dále je dáno číslo m (1 <= m <= 1000) a m tvrzení, z nichž
každé může mít jeden z dvou možných tvarů:
- Jako i-té je třeba otevřít dveře, na nichž je zvíře j, kde
1<=i,j<=n. Toto tvrzení budeme kódovat trojicí čísel 1 i j.
- Jako i-té je třeba otevřít dveře, na nichž je buď zvíře
j nebo zvíře k, kde 1<=i,j,k<=n, j<>k. Toto tvrzení budeme
kódovat čtveřicí čísel 2 i j k.
Řešením hlavolamu je takové pořadí otvírání dveří, ve kterém se
každé dveře vyskytnou právě jednou a které vyhovuje všem zadaným
tvrzením.
Vstupní soubor
Vstupní soubor
KURU.IN
obsahuje několik hlavolamů. První řádek
souboru je tvořen jediným číslem určujícím počet hlavolamů
v souboru. Pro každý hlavolam obsahuje vstupní soubor blok údajů.
Na prvním řádku bloku jsou uvedena čísla n a m. Každý z dalších
m řádků obsahuje kód jednoho tvrzení. Jednotlivé bloky údajů jsou
odděleny vždy jedním prázdným řádkem.
Výstupní soubor
Program vypíše do výstupního souboru KURU.OUT pro každý hlavolam
jeden řádek, který bude obsahovat:
- text
Neexistuje reseni
, pokud hlavolam nemá ani jedno řešení
- text
Vice reseni
, jestliže má hlavolam více než jedno řešení
- řešení hlavolamu, pokud má hlavolam právě jedno řešení
Řešením je posloupnost čísel zvířat vytesaných na dveřích
v takovém pořadí, v jakém je třeba dveře otvírat. Čísla jsou na
řádku oddělena vždy jednou mezerou.
Příklad
Soubor KURU.IN
2
4 4
2 1 1 2
2 2 4 3
2 3 2 4
2 2 1 4
3 1
1 1 2
Soubor KURU.OUT
1 4 2 3
Vice reseni