Nadesłany przez Krzysztof Kwiatkowski, 05 marca 2006 01:00
Kod przedstawiony poniżej przedstawia główną część rozwiązania problemu.Pobierz pełne rozwiązanie.
Jeżeli nie odpowiada Ci sposób formatowania kodu przez autora skorzystaj z pretty printer'a i dostosuj go automatycznie do siebie.
kod_graya_d.dpr:
// Generowanie podzbiorów zbioru n-elementowego za pomocą Kodu Grey’a.
// www.algorytm.org
// (c) 2006 Krzysztof Kwiatkowski
program kod_graya;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
vector = array[1..10] of Integer;
{
***************************************************************************
*
* Prosta implementacja funkcji f(x)=a^x.
*
***************************************************************************
}
function pow(pods: Integer; wyk: Integer): LongInt;
var
a: Integer;
begin
if ( pods = 0 ) then pods:=0
else if ( pods = 1) then pods:=1
else if ( wyk = 0) then pods:=1
else begin
if (wyk<0) then begin
writeln('Wykladnik mniejszy od 0. Nie obsluguje');
exit;
end;
a := pods;
while ( wyk > 1 ) do begin
dec(wyk);
pods:=pods*a;
end;
end;
pow:=pods;
end;
{
****************************************************
*
* Funkcja przeksztalcajaca liczbe calkowita
* na zapis dwojkowy. Wynikiem jest wektor
*
* Pierwsza liczba w zwracanym wektorze to ilosc elementow
* obliczonej liczby.
*
****************************************************
}
function ZmianaPodstawy2Wektor(pods: Integer; liczba: Integer): vector;
var
v,w: vector;
i,j: Integer;
begin
if (liczba<0) then begin
writeln('Liczba mniejsza od 0. Nie obsluguje');
exit;
end;
if (liczba=0) then begin
v[1]:=1;
v[2]:=0;
ZmianaPodstawy2Wektor:=v;
end;
i:=1;
while (liczba>0) do begin
inc(i);
v[i]:=liczba mod pods;
liczba:=liczba div pods;
end;
for j:=2 to i do w[j]:=v[i-j+2];
w[1]:=i-1;
ZmianaPodstawy2Wektor:=w;
end;
{
*****************************************************************************
*
* Ta funkcja przeszktalca liczbe z systemu o podstawie pods zapisanej
* w wektorze, do liczby w systemie dziesietnym.
* Podana liczba w wektorze v, musi miec specyficzna postac, tzn.
* pierwszy element tablicy to liczba mowiaca ile cyfr ma liczba
* do przeksztalcenia.
*
* np. v=[3,1,1,0]; (czyli w systemie dziesietnym jest to = 6)
*
*****************************************************************************
}
function ZmianaPodstwy2Liczba(pods: Integer; v: vector): Integer;
var
suma: Integer;
i,j : Integer;
begin
suma:=0;
j:=0;
for i:=v[1]+1 downto 2 do begin
suma:=suma+(v[i]*pow(pods,j));
inc(j);
end;
ZmianaPodstwy2Liczba:=suma;
end;
{
**********************************************************
*
* Funkcja na podstawie indexu generuje slowo Grey'a
*
**********************************************************
}
function IndeksNaSlowoGreya(i: Integer; ile_m: Integer):vector;
var
g,h: vector;
j,z: Integer;
begin
FillChar(h,sizeof(h),0);
g:=ZmianaPodstawy2Wektor(2,i);
if (ile_m<g[1]) then begin
writeln('Za mala liczba miejsc na ktorych nalezy przedstawic liczbe.');
writeln('Wychodze z funkcji.');
exit;
end;
for i:=2 to g[1]+1 do h[ile_m-g[1]+i-1]:=g[i];
for i:=1 to ile_m do begin
z:=ile_m-i+1;
g[ile_m-i+1]:=(h[z]+h[z-1]) mod 2;
end;
FillChar(h,sizeof(h),0);
h[1]:=ile_m;
for i:=2 to ile_m+1 do h[i]:=g[i-1];
IndeksNaSlowoGreya:=h;
end;
{ DORZUCIC GENEROWANIE G[n] ZA POMOCA ROZNICY SYMETRYCZNEJ }
function IndeksNaSlowoGreyaXOR(i: Integer; ile_m: Integer):vector;
var
g,h: vector;
j,z: Integer;
begin
FillChar(h,sizeof(h),0);
g:=ZmianaPodstawy2Wektor(2,i);
if (ile_m<g[1]) then begin
writeln('Za mala liczba miejsc na ktorych nalezy przedstawic liczbe.');
writeln('Wychodze z funkcji.');
exit;
end;
end;
{**************************************************************************
*
* Ta funkcja zwraca numer indeksu dla pobranego slowa Graya.
*
* Parametry
* v [in] - macierzy wyjsciowa zawierajaca w pierwszym elemencie
* warosc ile_m oraz w ile_m kolejnych elementow
* szukane slowo Grey'a
*
* n [out] - szukany indeks slowa Gray'a
*
**************************************************************************}
function SlowoGrayaNaIndeks(v:vector):integer;
var
b : vector;
i,j : Integer;
suma: Integer;
begin
b[1]:=v[1];
for j:=v[1]+1 downto 2 do begin
suma:=0;
for i:=j downto 2 do
suma:=suma+v[i];
b[j]:=suma mod 2;
end;
SlowoGrayaNaIndeks:=ZmianaPodstwy2Liczba(2,b);
end;
{***************************************************************************
*
* Funkcja ta generuje wektor przejsc korzystajac z tablic.
* Wektor przejsc zawiera numery bitow, ktore ulegaja zmianie w generowaniu
* kolejnych slow kodu Grey'a.
* Podawany argument n oraz dlugosc rozpatrywanych slow w kodzie Grey'a,
* maja taka sama wartosc.
*
* n [in] - dlugosc wektora wejsciowego
* Tout [out] - wygenerowany wektor przejsc
*
* UWAGA:
* Pierwszy element w wektorze wyjsciowym zawiera dlugosc tego wygenerowanego
* wektora.
***************************************************************************}
function GenerujWektorPrzejsc(n: Integer): vector;
var
i,k,Twsk,j: Integer;
flag : Boolean;
v,Tout : vector;
warunekZak: Integer;
begin
// inicjowanie wartosci poczatkowych
i:=1; Twsk:=2;
flag:=True;
warunekZak := pow(2,n)-1;
for j:=1 to n do v[j]:=j;
while flag do begin
if v[i]>0 then begin
Tout[Twsk]:=v[i];
inc(Twsk);
v[i]:=0;
for k:=i-1 downto 1 do v[k]:=k;
i:=1;
end else
inc(i);
// obliczamy wartosci do polowy, poniewaz wartosci w ciagu sa takie same
// jak wartosci w obliczonym ciagu ale od tylu.
// TO DO: dla n= 2 ten program nie dziala. Powodem jest ten warunek ponizej.
// Powoduje on wystepowanie petli nieskonczonej
if Twsk=( (warunekZak+1) div 2 ) then flag:=False;
end;
// wartosc 2^(n-1) jest zawsze rowna n (jest to srodek ciagu, miejsce
// w kodzie Grey'a gdzie pierwsza wartosc kodu zmienia sie z 0 na 1)
Tout[Twsk+1]:=n;
// TODO: nie wiem czemu ale cos sie kopie na tym wskazniku wiec ustwie go na twrado
Tout[Twsk]:=1;
// reszta juz jest znana - wiec przepisujemy
j:=0;
for i:=Twsk+2 to warunekZak+1 do begin
Tout[i]:=Tout[Twsk-j];
inc(j);
end;
Tout[1]:=warunekZak; //w pierwszym elemencie jest liczba okreslajaca dlugosc wektora przejsc
GenerujWektorPrzejsc:=Tout;
end;
// PONIZSZE PROCEDURY SA POTRZBNE DO GENEROWANIA PODZBIOROW I OGOLNIE DO
// DZIALANIA PROGRAMU.
// CALA TRUDNOSC ALGORYMU POLEGA NA WYZNACZENIU WEKTORA PRZEJSC.
// OPIS ALGORYTMU:
// 1. GENERUJEMY WEKTOR PRZEJSC
// 2. WYKORZYSTUJEMY TEN WEKTOR DO GENEROWANIA SLOW KODU GREYA
// 3. WYGENEROWANE SLOWO GREYA PODAJEMY DO PROCCEDURY PokazImiona(), KTORA
// WSTAWIA W MIEJSCE JEDYNEK ODPOWIEDNIE SLOWA (W TYM PRZYPADKU IMIONA)
var
i,n: Integer;
v,w: vector;
imie: array[1..10] of String;
procedure PodajImiona(n: integer);
var
i: Integer;
begin
for i:=1 to n do begin
write('Podaj imie ',i,': ');
Readln(imie[i]);
end;
end;
procedure PokazImiona(v: vector; n: Integer);
var
j: Integer;
begin
for j:=1 to n do
if (v[j]=1) then
write(imie[j],',');
writeln;
end;
procedure GenerujPodzbiory;
begin
// nmax dla tablicy w typie vector jest ustawione na 1025
// wiec maxymalna liczba elementow w slowie Gray'a nie moze byc wieksza niz 10
w:=GenerujWektorPrzejsc(n);
for i:=1 to n do
v[i]:=0;
// wystarczy tak bo tylko jedna liczba sie zmienia w jednym przejsciu
for i:=1 to w[1] do begin
if (v[w[i+1]] = 0) then
v[w[i+1]]:=1
else
v[w[i+1]]:=0;
write(i:2,': ');
PokazImiona(v,n);
end;
end;
begin
Write('Ilosc elementow (wartosc od 2 do 10): '); Readln(n);
PodajImiona(n);
GenerujPodzbiory;
readln;
end.

