Nadesłany przez Michał Knasiecki, 09 sierpnia 2005 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.
prim_d/Unit1.pas:
//Program pobrany ze strony www.algorytm.org //Opracowal Michal Knasiecki //UWAGA!!!!!!!!!!! {Przykladowy graf jest zapisany w pliku graf.txt Struktura pliku jest następująca: Rozmiar :waga:waga:...waga: :waga:waga:...Waga: ................... :waga:waga:...Waga: Gdzie liczba kolumn i wierszy macierzy jest równa rozmiarowi. Jesli waga=0 to nie istnieje krawędź lącząca odpowiednie wierzcholki} unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Menus, StdCtrls; type TForm1 = class(TForm) MainMenu1: TMainMenu; Plik1: TMenuItem; Wczytajlist1: TMenuItem; Wyczy1: TMenuItem; N1: TMenuItem; Zakocz1: TMenuItem; ListBox1: TListBox; Button1: TButton; Memo1: TMemo; OpenDialog1: TOpenDialog; Button2: TButton; Label1: TLabel; SaveDialog1: TSaveDialog; N2: TMenuItem; Zapiszraport1: TMenuItem; Label2: TLabel; Label3: TLabel; procedure Button1Click(Sender: TObject); procedure Wczytajlist1Click(Sender: TObject); procedure Wyczy1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Zakocz1Click(Sender: TObject); procedure Zapiszraport1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; wsk=^list; list=record vert:integer; waga:integer; next:wsk; end; EdgeList=^edge; edge=record pop:integer; nast:integer; waga:integer; next:edgelist; end; TCzas=class start,stop:Tdatetime; function Podaj:Tdatetime; function Oblicz:integer; end; var Form1: TForm1; first:edgelist; tablica:array of wsk; current:wsk; currlist:edgelist; time,id,n:integer; czas:tczas; d,p,f:array of integer; connected:boolean; globalX,globalY,globalW:integer; tree:array of boolean; treeN:integer; koszt:integer; implementation {$R *.DFM} function tczas.Podaj:TDateTime; begin Result:=Now; end; function Tczas.Oblicz:integer; begin result:=trunc(TimeStampToMSecs(DateTimeToTimeStamp(czas.stop))- TimeStampToMSecs(DateTimeToTimeStamp(czas.start))); end; procedure AddToList(tab:integer;vert:integer;waga:integer;var current:wsk); var prev,next:wsk; t:boolean; begin t:=false; if tablica[tab]=nil then t:=true; if tablica[tab]<>nil then begin prev:=current; next:=current^.next; end else begin prev:=nil; next:=nil; end; new(current); current^.vert:=vert; current^.waga:=waga; current^.next:=next; if prev<>nil then prev^.next:=current; if t=true then tablica[tab]:=current; end; procedure Removeall2; var tmp,next:edgelist; begin tmp:=first; while tmp<>nil do begin next:=tmp^.next; dispose(tmp); tmp:=next; end; end; procedure Removeall(tab:integer); var next:wsk; begin if tablica[tab]<>nil then begin next:=tablica[tab]; repeat if next<>nil then current:=next; {if current=tablica[tab] then form1.listbox1.items.add('Wierzcholek: '+inttostr(current^.vert)) else form1.listbox1.items.add(inttostr(current^.vert));} next:=current^.next; {if remove=true then} if current<>tablica[tab] then dispose(current) else tablica[tab]:=nil; until next=nil; end; end; procedure Wypisz(tab:integer); var next:wsk; begin if tablica[tab]<>nil then begin next:=tablica[tab]; repeat if next<>nil then current:=next; if form1.ListBox1.Items.Capacity<32000 then if current=tablica[tab] then form1.listbox1.items.add('Wierzcholek: '+inttostr(current^.vert)) else form1.listbox1.items.add(inttostr(current^.vert)+' ['+inttostr(current^.waga)+']'); next:=current^.next; until next=nil; end; end; procedure TForm1.Button1Click(Sender: TObject); var i:integer; begin listbox1.clear; for i:=1 to n do wypisz(i); end; function podajwage(s:string;i:integer):integer; var p,j:integer; c:string[1]; tmp:string; begin j:=0; p:=1; repeat c:=s[p]; inc(p); if c=':' then inc(j); until j=i; tmp:=''; repeat c:=s[p]; inc(p); if c<>':' then tmp:=tmp+c; until c=':'; result:=strtoint(tmp); end; procedure TForm1.Wczytajlist1Click(Sender: TObject); var f:textfile; s:string; waga,i,j:integer; begin if opendialog1.execute then begin assignfile(f,opendialog1.filename); reset(f); readln(f,s); n:=strtoint(s); setlength(tablica,n+1); current:=nil; for i:=1 to n do begin readln(f,s); for j:=1 to n do begin if j=1 then addtolist(i,i,0,current); {***********} waga:=podajwage(s,j); if waga>0 then addtolist(i,j,waga,current); // if strtoint(s[j])>0 then addtolist(i,j,waga,current); end; end; closefile(f); memo1.lines.add('> Graf wczytany...'); memo1.lines.add('> Liczba wierzchołków: '+inttostr(n)); memo1.lines.add('> Liczba krawędzi: '+inttostr(round((n+(n*(n-3)/2))*0.6))); end; end; procedure TForm1.Wyczy1Click(Sender: TObject); var i:integer; begin for i:=1 to n do removeall(i); removeall2; finalize(tablica); end; procedure TForm1.FormCreate(Sender: TObject); begin czas:=tczas.create; end; function next(w:wsk):integer; begin if w^.next<>nil then begin current:=w^.next; result:=current^.vert; end else result:=0; end; procedure Visit(v: Integer); {proc. rekurencyjnego odwiedzania wierzch.} var i:integer; begin if id<>1 then connected:=false; D[v]:=time; {przydzielenie numerka w numeracji pre-order} Inc(time); current:=tablica[v]; repeat i:=next(current); if i>0 then begin if D[i]=-1 then {jesli wierzch. i jest bialy to ...} begin P[i]:=v; {zaznaczamy, ze to z wierzch. v przechozimy do i} Visit(i); {przechodzimy rekurencyjnie do wierzch. i} end end; until i=0; F[v]:=time; {przydzielenie numerka w numeracji post-order} Inc(time); end; procedure DFS; var i:integer; begin for i:=1 to N do begin D[i]:=-1;F[i]:=-1; {oznaczamy wszystkie wierzcholki jako biale} {Uwaga! wierzch. biale maja obie wartosci rowne -1; czarne - obie rozne od -1; szare - D rozne od -1, F rowne -1} end; time:=1; {zmienna potrzebna do numeracji} for i:=1 to N do if D[i]=-1 then {jesli wierzch. i jest bialy to ...} begin id:=i; P[i]:=-1; {zaznaczamy, ze wierzch. i jest jednym z wierzch. startowych} Visit(i); {przechodzimy do wierzch. i} end; end; procedure usun(x,y:integer); var tmp,prev,next:wsk; begin tmp:=tablica[x]; repeat prev:=tmp; tmp:=tmp^.next; until tmp^.vert=y; next:=tmp^.next; prev^.next:=next; dispose(tmp); end; //Procedury Listy krawędzi procedure AddToEdgeList(pop,nast,waga:integer{;var current:edgelist}); var prev,next:edgelist; begin if currlist<>nil then begin prev:=currlist; next:=currlist^.next; end else begin prev:=nil; next:=nil; end; new(currlist); currlist^.pop:=pop; currlist^.nast:=nast; currlist^.waga:=waga; currlist^.next:=next; if first=nil then first:=currlist; if prev<>nil then prev^.next:=currlist; end; procedure findLess(waga:integer{;var first,current:edgelist}); var tmp,next:edgelist; begin if first<>nil then begin next:=first; tmp:=next; repeat if (next^.next<>nil) then begin tmp:=next; next:=next^.next end; until (next^.next=nil)or(next.waga>waga); if next.waga>waga then currlist:=tmp else currlist:=next; end; end; procedure addtotree(v:integer;w:integer); var tmp:wsk; begin if tree[v]=false then begin //showmessage(inttostr(v)+':'+inttostr(w)); inc(treen); // form1.listbox2.items.add(inttostr(v)); tree[v]:=true; inc(koszt,w); tmp:=tablica[v]^.next; while tmp<>nil do begin // showmessage(inttostr(tmp^.vert)); findless(tmp^.waga); addtoedgelist(v,tmp^.vert,tmp^.waga); tmp:=tmp^.next; end; // findless(); end; end; procedure pobierz; var tmp:edgelist; f:edgelist; begin f:=first^.next; if f{irst}<>nil then begin globalx:=f{irst}^.pop; globalY:=f{irst}^.nast; GlobalW:=f{irst}^.waga; tmp:=f{irst}^.next; dispose(f{irst}); first^.next:=tmp; end else begin globalx:=0; globaly:=0; globalw:=0; end; end; procedure TForm1.Button2Click(Sender: TObject); var i:integer; //next:edgelist; begin //Spójnosc setlength(p,n+1); setlength(d,n+1); setlength(f,n+1); connected:=true; memo1.lines.add('> Badanie spójności grafu...'); dfs; finalize(p); finalize(d); finalize(f); if connected=false then memo1.lines.add('> Graf nie jest spójny') else memo1.lines.add('> Graf jest spójny'); begin memo1.lines.add('> Budowanie listy krawędzi...'); //Przepisanie listy sąsiedztwa do listy krawędzi memo1.lines.Add('> Szukanie drzewa...'); setlength(tree,n+1); for i:=1 to n do tree[i]:=false; first:=nil; currLIST:=nil; addtoedgelist(0,0,0); currLIST:=nil; treen:=0; koszt:=0; czas.start:=czas.podaj; addtotree(1,0); repeat pobierz; addtotree(globaly,globalw); until treen=n; czas.stop:=czas.podaj; finalize(tree); memo1.lines.Add('> Znaleziono w '+inttostr(czas.oblicz)+' [ms]'); memo1.lines.Add('> Minimalny koszt wynosi '+inttostr(koszt)); end; end; procedure TForm1.Zakocz1Click(Sender: TObject); begin application.terminate; end; procedure TForm1.Zapiszraport1Click(Sender: TObject); begin if savedialog1.execute then begin memo1.lines.SaveToFile(savedialog1.filename); end; end; end.