Wstęp do programowania / Ćwiczenia 6: Różnice pomiędzy wersjami

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
m
Linia 35: Linia 35:
  
 
{{rozwiazanie|||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">  
 
{{rozwiazanie|||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">  
Główną trudnością jest wymyślenie odpowiedniego niezmiennika pętli while. Tu, będzie to zdanie:
+
Główną trudnością jest wymyślenie odpowiedniego niezmiennika pętli while. Tu będzie to zdanie:
 
  &forall; i  (1 &le; i < m) &rArr;  A[i] < 0 &and;   
 
  &forall; i  (1 &le; i < m) &rArr;  A[i] < 0 &and;   
 
  &forall; j  (m &le; j < r) &rArr;  A[j] = 0 &and;   
 
  &forall; j  (m &le; j < r) &rArr;  A[j] = 0 &and;   
Linia 145: Linia 145:
 
   
 
   
 
{{cwiczenie|||
 
{{cwiczenie|||
Tablica A typu array[1..N] of integer, N >0, zawiera tylko liczby dodatnie. Napisz program który dla danego W typu integer takiego, że W > 0 sprawdza, czy w A istnieje segment o sumie W (czyli czy istnieją l, p takie, że W<math>=A[l]+...+A[p-1]</math>).}}
+
Tablica A typu array[1..N] of integer, N >0  zawiera tylko liczby dodatnie. Napisz program, który dla danego W typu integer takiego, że W > 0 sprawdza, czy w A istnieje segment o sumie W (czyli czy istnieją l, p takie, że W<math>=A[l]+...+A[p-1]</math>).}}
  
 
'''Program'''
 
'''Program'''
Linia 223: Linia 223:
 
  1 &le; l &le; p+1 &le; N+1 &and; N,W > 0 &and; suma+A[p]=A[l]+....A[p] &and;
 
  1 &le; l &le; p+1 &le; N+1 &and; N,W > 0 &and; suma+A[p]=A[l]+....A[p] &and;
 
  A jest tablicą o wartościach dodatnich
 
  A jest tablicą o wartościach dodatnich
Jedyna część, która nie jest oczywista to, że A[l]+...A[p-1] < W, ale to wynika z  (suma < W) i suma=A[l]+....A[p-1]
+
Jedyna część, która nie jest oczywista, to że A[l]+...A[p-1] < W, ale to wynika z  (suma < W) i suma=A[l]+....A[p-1]
  
 
'''5''' W drugiej gałęzi wiemy dodatkowo, że suma > W
 
'''5''' W drugiej gałęzi wiemy dodatkowo, że suma > W
Linia 237: Linia 237:
 
Dla uzasadnienia drugiej linii wystarczy zauważyć, że gdy skracamy segment o wartości mniejszej niż W, to jego wartość spada, bo A jest tablica dodatnią.
 
Dla uzasadnienia drugiej linii wystarczy zauważyć, że gdy skracamy segment o wartości mniejszej niż W, to jego wartość spada, bo A jest tablica dodatnią.
  
Pozostaje uzasadnienie  l+1 &le; p. Ponieważ suma > W to l < p, a więc też l+1 &le; p.  
+
Pozostaje uzasadnienie  l+1 &le; p. Ponieważ suma > W to l < p, a więc też l+1 &le; p.  
  
 
'''7''' Po pętli '''while''' wiemy, że zachodzi N(l,p,suma) i zaprzeczenie dozoru, czyli (suma=W &or; p > N). Z niezmiennika wiemy, że p &le; N+1, a więc musi być p=N+1.
 
'''7''' Po pętli '''while''' wiemy, że zachodzi N(l,p,suma) i zaprzeczenie dozoru, czyli (suma=W &or; p > N). Z niezmiennika wiemy, że p &le; N+1, a więc musi być p=N+1.
Linia 361: Linia 361:
 
'''5''' Kolejny '''if'''; dowód znów się rozgałęzia.
 
'''5''' Kolejny '''if'''; dowód znów się rozgałęzia.
  
'''6''' Korzystając z reguły na przypisanie, mamy do pokazania, że N(i,ile,kand) &and; i &le; N &and; A[i]<> kand i &and; ile > 0 implikuje N(i+1,ile-1,kand). Jesli P to permutacja z N(i,ile,kand), to
+
'''6''' Korzystając z reguły na przypisanie, mamy do pokazania, że N(i,ile,kand) &and; i &le; N &and; A[i]<> kand i &and; ile > 0 implikuje N(i+1,ile-1,kand). Jeśli P to permutacja z N(i,ile,kand), to
 
szukana permutacja to P rozszerzona o identyczność na i. W nowym ogonie mamy dodatkowo A[i] i kand. Z tego wynika, że gdyby A[i] był liderem w nowym ogonie, to A[i] byłby liderem w starym ogonie, co jest niemożliwe. Oczywiście i+1 &le; N+1; oraz ile > 0.
 
szukana permutacja to P rozszerzona o identyczność na i. W nowym ogonie mamy dodatkowo A[i] i kand. Z tego wynika, że gdyby A[i] był liderem w nowym ogonie, to A[i] byłby liderem w starym ogonie, co jest niemożliwe. Oczywiście i+1 &le; N+1; oraz ile > 0.
  
 
'''7''' Wpierw zauważmy, że ile &le; 0 oraz ile &ge; 0 implikują ile=0. Korzystając z reguły na przypisanie, mamy do pokazania, że
 
'''7''' Wpierw zauważmy, że ile &le; 0 oraz ile &ge; 0 implikują ile=0. Korzystając z reguły na przypisanie, mamy do pokazania, że
 
N(i,ile,kand) &and; i &le; N &and; A[i] <> kand &and; ile =0  
 
N(i,ile,kand) &and; i &le; N &and; A[i] <> kand &and; ile =0  
implikuje N(i+1,1,A[i]). Ponieważ ile=0 to w tablicy A[1..i-1] nie ma lidera. Szukaną permutacją jest więc na przykład A[i]@A[1..i-1].
+
implikuje N(i+1,1,A[i]). Ponieważ ile=0, to w tablicy A[1..i-1] nie ma lidera. Szukaną permutacją jest więc na przykład A[i]@A[1..i-1].
 
Oczywiście i+1 &le; N+1; oraz ile > 0.
 
Oczywiście i+1 &le; N+1; oraz ile > 0.
  
 
'''8''' Po wyjściu z pętli mamy N(i,ile,kand) i zaprzeczenie dozoru, czyli i > N. To oznacza, że i=N+1. Czy możliwe jest, by liderem była
 
'''8''' Po wyjściu z pętli mamy N(i,ile,kand) i zaprzeczenie dozoru, czyli i > N. To oznacza, że i=N+1. Czy możliwe jest, by liderem była
wartośc w <> kand. Jeśli tak przypuścimy, to niezależnie od ile, w musiałaby być liderem w ogonie, co jest sprzeczne z niezmiennikiem. Jedynym kandydatem na lidera jest więc rzeczywiście kand.
+
wartośc w <> kand? Jeśli tak przypuścimy, to niezależnie od ile, w musiałaby być liderem w ogonie, co jest sprzeczne z niezmiennikiem. Jedynym kandydatem na lidera jest więc rzeczywiście kand.
  
 
</div>
 
</div>

Wersja z 22:18, 15 lis 2006

<<< Powrót do modułu Dowodzenie poprawności programów

To są zadania na logikę Hoare'a.

Oglądaj wskazówki i rozwiązania __SHOWALL__
Ukryj wskazówki i rozwiązania __HIDEALL__


Zadanie 1 (Flaga trójkolorowa)

Udowodnij częściową poprawność podanego poniżej rozwiązania zadania o fladze trójkolorowej.

Ćwiczenie

Dana jest tablica A typu array[1..N] of integer (N > 0). Należy tak poprzestawiać w niej elementy, żeby najpierw były elementy ujemne, potem równe zero, a na końcu dodatnie.

Program

program FlagaTrójkolorowa(N:integer; A:array[1..N] of integer);
var m,r,w,pom : integer;
begin
  m:=1; r:=1; w:=N;
  while r <= w do 
    if A[r]=0 then r:=r+1			//przedłużamy segment liczb dodatnich	
    else 
      if A[r]<0 then begin			
        pom:=A[r]; A[r]:=A[m]; A[m]:=pom;	//zamieniamy wartości w A[r] i A[m], po zamianie A[r]=0 i A[m] < 0  
        m:=m+1;					//więc zwiększamy oba indeksy r i m
        r:=r+1;
      end
      else begin
        pom:=A[r]; A[r]:=A[w]; A[w]:=pom;	//zamieniamy wartości w A[r] i A[w]
        w:=w-1;					//po zamianie A[w]>0,  ale o A[r] nic nie wiemy
      end;			     
end.

Rozwiązanie

{{{3}}}

Całkowita poprawność

Zadanie 2 (Segment o danej sumie)

Udowodnij częściową poprawność dla podanego poniżej zadania i jego rozwiązania.

Ćwiczenie

Tablica A typu array[1..N] of integer, N >0 zawiera tylko liczby dodatnie. Napisz program, który dla danego W typu integer takiego, że W > 0 sprawdza, czy w A istnieje segment o sumie W (czyli czy istnieją l, p takie, że W).

Program

program SegmentODanejSumie2(N,W:integer; A:array[1..N] of integer);
//Tablica A zawiera tylko liczby dodatnie
var l,p,suma: integer;
    znalezione: boolean;
begin
  l:=1; p:=1;
  suma:=0;
  while (suma <> W) and (p <= N) do
    if suma < W then begin		//jeśli suma jest za mała, to przesuwamy prawy koniec segmentu
      suma:=suma+A[p];
      p:=p+1;
    end
    else begin			//jeśli za duża, to przesuwamy lewy koniec segmentu
      suma:= suma-A[l];
      l:=l-1;
    end;
  while (suma > W) do begin  
    suma:= suma-A[l];
    l:=l-1;
  end;
  znalezione:=(suma=W);
end.

Rozwiązanie

{{{3}}}

Całkowita poprawność

Zadanie 3 (Głosowanie większościowe)

Udowodnij częściową poprawność dla podanego poniżej zadania i jego rozwiązania.

Ćwiczenie

Dana jest tablica A typu array[1..N] of integer, N > 0. Sprawdź, czy jest w niej element wystepujący więcej niż N/2 razy i jeśli tak, wskaż go.

Program

program Głosowanie2(N,W:integer; A:array[1..N] of integer);
var ile,i,kand,lider: integer;
begin
  kand:=A[1];		//szukamy kandydata na lidera
  ile := 1;
  i:=2;
  while i <= N do begin	
    if A[i]=kand then begin
      ile:=ile+1;
      i:=i+1;
    end
    else
      if ile > 0 then begin
        ile:=ile-1;
        i:=i+1;
      end
      else begin
        kand:=A[i];
        ile:=1;
        i:=i+1;
      end;
  end;
  ile:=0;		//sprawdzamy, czy kandydat jest liderem
  for i:=1 to do 
    if A[i]=kand then ile:=ile+1; 
  if (ile >= (N div 2 + 1) then begin 
    lider:=kand;
    write('Liderem jest: ', kand);
  end 
  else 
    lider:=0;
end.

Rozwiązanie

{{{3}}}

Zadanie 4 (BinPower)

Udowodnij częściową poprawność dla podanego poniżej zadania i jego rozwiązania.

Ćwiczenie

Dla zadanych x,n > 0 wyznacz xn (oczywiscie bez exp i ln).

Program

function BinPower(x,n:integer):integer;
// Dla x,n > 0 wyznaczamy x do potęgi n 
var z,y,i: integer;
begin
  z:=1;
  y:=x;
  i:=n;
  while i > 0 do begin
    if (i mod 2 = 1) then z:=z*y;
    y:=y*y;
    i:=i div 2;
  end;
  BinPower:=z;
end;

Rozwiązanie

{{{3}}}