Professional Documents
Culture Documents
Giao Trinh
Giao Trinh
1.Thuật toán duyệt đồ thị theo chiều rộng để tìm đường đi ngắn
nhất từ đỉnh xp đến kt
Dữ liệu vào:
+ Dòng đầu tiền chứa n là số đỉnh của đồ thị (n≤ 200)
+Dòng thứ hai chứa các đỉnh xp, kt
+Các dòng tiếp, mỗi dòng chứa hai số u,v thể hiện có cạnh nối u và v
Dữ liệu ra:
+Dòng đầu tiên ghi S là số đỉnh trên đường đi ngắn nhất
+Dòng thứ hai ghi S số nguyên là tên các đỉnh lần lượt trên đường đi.
Chương trình:
{$A+,B-,D+,E+,F-,G-,I+,L+,N+,O-,P-,Q+,R+,S+,T-,V+,X+
,Y+}
{$M 16384,0,655360}
uses crt;
const
tfi='INP.TXT';
tfo='OUT.TXT';
maxN=200;
var
fi,fo: text;
Gr: array[1..maxN,1..maxN] of byte;
N: integer;
xp,kt: integer;
Q: array[1..maxN] of integer;
qf,ql: integer;
Tr: array[1..maxN] of integer;
x: array[1..maxN] of integer;
slx: integer;
procedure InitQ;
begin
qf:=1;
ql:=1;
end;
procedure Put(u: integer);
begin
q[ql]:=u;
Lê Thanh Bình 2
inc(ql);
end;
function Get: integer;
begin
Get:=q[qf];
inc(qf);
end;
function Qempty: boolean;
begin
Qempty:=(qf=ql);
end;
procedure Docdl;
var u,v: integer;
begin
fillchar(Gr,sizeof(Gr),0);
readln(fi,N);
readln(fi,xp,kt);
while not seekeof(fi) do
begin
readln(fi,u,v);
Gr[u,v]:=1;
Gr[v,u]:=1;
end;
end;
procedure DuyetCR;
var u,v: integer;
begin
InitQ;
fillchar(Tr,sizeof(Tr),0);
Put(xp); Tr[xp]:=-1;
repeat
u:=Get;
for v:=1 to N do
if (Gr[u,v]=1) and (Tr[v]=0) then
begin
Put(v);
Tr[v]:=u;
if v=kt then exit;
end;
until Qempty;
end;
Lê Thanh Bình 3
procedure TimDuong;
var u: integer;
begin
slx:=0;
if Tr[kt]=0 then exit;
u:=kt;
repeat
inc(slx);
x[slx]:=u;
u:=Tr[u];
until u=-1;
end;
procedure Inkq;
var i: integer;
begin
writeln(fo,slx);
for i:=slx downto 1 do write(fo,x[i],' ');
end;
BEGIN
clrscr;
assign(fi,tfi); reset(fi);
assign(fo,tfo); rewrite(fo);
Docdl;
DuyetCR;
TimDuong;
Inkq;
close(fi); close(fo);
END.
2. Thuật toán duyệt đồ thị theo chiều sâu để tìm các thành phần
liên thông của đồ thị vô hướng.
Dữ liệu vào:
+Dòng đầu tiên ghi số n là số đỉnh của đồ thị (n≤ 200)
+Các dòng tiếp theo, mỗi dòng ghi hai số nguyên u,v thể hiện có cạnh nối u
và v
Dữ liệu ra:
+Dòng đầu tiên ghi K là số thành phần liên thông của đồ thị
+K dòng tiếp theo, mỗi dòng ghi danh sách các đỉnh của một thành phần liên
thông
Lê Thanh Bình 4
{$A+,B-,D+,E+,F-,G-,I+,L+,N+,O-,P-,Q+,R+,S+,T-,V+,X+
,Y+}
{$M 65520,0,655360}
uses crt;
const
tfi='INP.TXT';
tfo='OUT.TXT';
maxN=200;
var
fi,fo: text;
Gr: array[1..maxN,1..maxN] of byte;
N: integer;
LT: array[1..maxN] of integer;
soLT: integer;
procedure Docdl;
var u,v: integer;
begin
Fillchar(Gr,sizeof(Gr),0);
readln(fi,N);
while not seekeof(fi) do
begin
readln(fi,u,v);
Gr[u,v]:=1;
Gr[v,u]:=1;
end;
end;
procedure TimTPLT;
var i: integer;
begin
Lê Thanh Bình 5
Fillchar(LT,sizeof(LT),0);
soLT:=0;
for i:=1 to N do
if LT[i]=0 then
begin
Inc(soLT);
Loang(i);
end;
end;
procedure Inkq;
var i,j: integer;
begin
writeln(fo,soLT);
for i:=1 to soLT do
begin
for j:=1 to N do
if LT[j]=i then write(fo,j,' ');
writeln(fo);
end;
end;
BEGIN
clrscr;
assign(fi,tfi); reset(fi);
assign(fo,tfo); rewrite(fo);
Docdl;
TimTPLT;
Inkq;
close(fi); close(fo);
END.
uses crt;
const
tfi='INP.TXT';
tfo='OUT.TXT';
maxN=200;
Lê Thanh Bình 6
var
fi,fo: text;
Gr: array[1..maxN,1..maxN] of byte;
N: integer;
LT: array[1..maxN] of integer;
soLT: integer;
S: array[1..maxN] of integer;
sn: integer;
procedure InitS;
begin
sn:=0;
end;
procedure Push(u: integer);
begin
inc(sn);
S[sn]:=u;
end;
function Pop: integer;
begin
Pop:=S[sn];
dec(sn);
end;
function Sempty: boolean;
begin
Sempty:=(Sn=0);
end;
procedure Docdl;
var u,v: integer;
begin
Fillchar(Gr,sizeof(Gr),0);
readln(fi,N);
while not seekeof(fi) do
begin
readln(fi,u,v);
Gr[u,v]:=1;
Gr[v,u]:=1;
end;
end;
begin
InitS;
Push(xp); LT[xp]:=soLT;
repeat
u:=Pop;
for v:=1 to N do
if (Gr[u,v]=1) and (LT[v]=0) then
begin
Push(v);
LT[v]:=soLT;
end;
until Sempty;
end;
procedure TimTPLT;
var i: integer;
begin
Fillchar(LT,sizeof(LT),0);
soLT:=0;
for i:=1 to N do
if LT[i]=0 then
begin
Inc(soLT);
DuyetCS(i);
end;
end;
procedure Inkq;
var i,j: integer;
begin
writeln(fo,soLT);
for i:=1 to soLT do
begin
for j:=1 to N do
if LT[j]=i then write(fo,j,' ');
writeln(fo);
end;
end;
BEGIN
clrscr;
assign(fi,tfi); reset(fi);
assign(fo,tfo); rewrite(fo);
Docdl;
Lê Thanh Bình 8
TimTPLT;
Inkq;
close(fi); close(fo);
END.
5 0 4 0 1
3. Thuật toán tìm các thành phần liên thông mạnh bằng phương
pháp duyệt đồ thị theo chiều sâu.
Dữ liệu vào:
+Dòng đầu tiên ghi N là số đỉnh của đồ thị
+Các dòng tiếp theo, mỗi dòng ghi hai số u,v thể hiện có cạnh nối từ u đến v
Dữ liệu ra:
+Dòng đầu tiên ghi K là số thành phần liên thông mạnh
+K dòng tiếp theo, mỗi dòng ghi danh sách các đỉnh thuộc một thành phần
liên thông mạnh.
Chuơng trình:
{$A+,B-,D+,E+,F-,G-,I+,L+,N+,O-,P-,Q+,R+,S+,T-,V+,X+
,Y+}
{$M 16384,0,655360}
uses crt;
const
tfi='INP.TXT';
tfo='OUT.TXT';
maxN=200;
var
fi,fo: text;
Gr: array[1..maxN,1..maxN] of byte;
N: integer;
TT: array[1..maxN] of integer;
CS: array[1..maxN] of integer;
sTT: integer;
LT: array[1..maxN] of integer;
soLT: integer;
procedure Docdl;
var u,v: integer;
begin
Fillchar(Gr,sizeof(Gr),0);
readln(fi,N);
Lê Thanh Bình 10
procedure DuyetXuoi;
var i: integer;
begin
Fillchar(TT,sizeof(TT),0);
sTT:=0;
for i:=1 to N do
if TT[i]=0 then LXuoi(i);
end;
procedure Sapxep;
var i,j: integer;
begin
for i:=1 to N do cs[i]:=i;
for i:=1 to N-1 do
for j:=i+1 to N do
if TT[i]<TT[j] then
begin
Doicho(TT[i],TT[j]);
Doicho(cs[i],cs[j]);
Lê Thanh Bình 11
end;
end;
procedure DuyetNguoc;
var i: integer;
begin
fillchar(LT,sizeof(LT),0);
soLT:=0;
for i:=1 to N do
if LT[cs[i]]=0 then
begin
inc(soLT);
Lnguoc(cs[i]);
end;
end;
procedure TimLTM;
begin
DuyetXuoi;
SapXep;
DuyetNguoc;
end;
procedure Inkq;
var i,j: integer;
begin
writeln(fo,soLT);
for i:=1 to soLT do
begin
for j:=1 to N do
if LT[j]=i then write(fo,j,' ');
writeln(fo);
end;
end;
Lê Thanh Bình 12
BEGIN
assign(fi,tfi); reset(fi);
assign(fo,tfo); rewrite(fo);
Docdl;
TimLTM;
Inkq;
close(fi); close(fo);
END.
4. Thuật toán tìm danh sách các đỉnh bản lề của đồ thị liên thông
bằng phương pháp duyệt đồ thị theo chiều sâu.
Dữ liệu vào:
+Dòng đầu tiên ghi N là số đỉnh của đồ thị
+Các dòng tiếp theo mỗi dòng ghi hai số u,v thể hiện có cạnh nối giữa u và v
Dữ liệu ra:
+Dòng đầu tiên ghi K là số đỉnh bản lề
+Dòng thứ hai ghi K số là tên của các đỉnh bản lề
Chương trình
{$A+,B-,D+,E+,F-,G-,I+,L+,N+,O-,P-,Q+,R+,S+,T-,V+,X+
,Y+}
{$M 65520,0,655360}
uses crt;
const
tfi='INP.TXT';
tfo='OUT.TXT';
maxN=200;
var
fi,fo: text;
Gr: array[1..maxN,1..maxN] of byte;
N: integer;
BL: array[1..maxN] of boolean;
TT: array[1..maxN] of integer;
pre: array[1..maxN] of integer;
sTT: integer;
procedure Docdl;
var u,v: integer;
Lê Thanh Bình 13
begin
Fillchar(Gr,sizeof(Gr),0);
readln(fi,N);
while not seekeof(fi) do
begin
readln(fi,u,v);
Gr[u,v]:=1;
Gr[v,u]:=1;
end;
end;
procedure TimBL;
var m,dem,i: integer;
begin
Fillchar(BL,sizeof(BL),false);
Fillchar(TT,sizeof(TT),0);
Fillchar(pre,sizeof(pre),0);
dem:=0;
TT[1]:=1;
sTT:=1;
for i:=2 to N do
if (Gr[1,i]=1) and (TT[i]=0) then
begin
Lê Thanh Bình 14
inc(dem);
m:=TinhMin(1,i);
end;
if dem>1 then BL[1]:=true;
end;
procedure Inkq;
var d,i: integer;
begin
d:=0;
for i:=1 to N do
if BL[i] then inc(d);
writeln(fo,d);
for i:=1 to N do
if BL[i] then write(fo,i,' ');
end;
BEGIN
assign(fi,tfi); reset(fi);
assign(fo,tfo); rewrite(fo);
Docdl;
TimBL;
Inkq;
close(fi); close(fo);
END.
5. Thuật toán tìm các thành phần song liên thông (dựa vào việc
tìm các thành phần liên thông mạnh trên đồ thị đã định hướng lại)
Dữ liệu vào:
+Dòng đầu tiên ghi N là số đỉnh của đồ thị
+Các dòng tiếp theo, mỗi dòng ghi hai số u,v thể hiện có cạnh nối u và v
Dữ liệu ra:
+Dòng đầu tiên ghi K là số thành phần song liên thông
+K dòng tiếp theo, mỗi dòng ghi danh sách các đỉnh của một thành phần liên
thông
Chương trình:
{$A+,B-,D+,E+,F-,G-,I+,L+,N+,O-,P-,Q+,R+,S+,T-,V+,X+
,Y+}
{$M 65520,0,655360}
Lê Thanh Bình 15
uses crt;
const
tfi='INP.TXT';
tfo='OUT.TXT';
maxN=200;
var
fi,fo: text;
Gr: array[1..maxN,1..maxN] of byte;
N: integer;
TT: array[1..maxN] of integer;
CS: array[1..maxN] of integer;
sTT: integer;
LT: array[1..maxN] of integer;
soLT: integer;
procedure Docdl;
var u,v: integer;
begin
Fillchar(Gr,sizeof(Gr),0);
readln(fi,N);
while not seekeof(fi) do
begin
readln(fi,u,v);
Gr[u,v]:=1;
Gr[v,u]:=1;
end;
end;
procedure DinhHuong;
var i: integer;
begin
fillchar(TT,sizeof(TT),0);
sTT:=0;
for i:=1 to N do
if TT[i]=0 then Lxuoi(i);
end;
procedure Sapxep;
var i,j: integer;
begin
for i:=1 to N do cs[i]:=i;
for i:=1 to N-1 do
for j:=i+1 to N do
if TT[i]<TT[j] then
begin
Doicho(TT[i],TT[j]);
Doicho(CS[i],CS[j]);
end;
end;
procedure Lnguoc(u:integer);
var v: integer;
begin
LT[u]:=soLT;
for v:=1 to N do
if (Gr[v,u]=1) and (LT[v]=0) then
Lnguoc(v);
end;
procedure DuyetNguoc;
var i: integer;
begin
Lê Thanh Bình 17
Fillchar(LT,sizeof(LT),0);
soLT:=0;
for i:=1 to N do
if (LT[cs[i]]=0) then
begin
Inc(soLT);
Lnguoc(cs[i]);
end;
end;
procedure TraHuong;
var i,j: integer;
begin
for i:=1 to N-1 do
for j:=i+1 to N do
begin
if Gr[i,j]=1 then Gr[j,i]:=1 else
if Gr[j,i]=1 then Gr[i,j]:=1;
end;
end;
procedure TimSLT;
begin
DinhHuong;
Sapxep;
DuyetNguoc;
TraHuong;
end;
procedure Inkq;
var i,j: integer;
begin
writeln(fo,soLT);
for i:=1 to soLT do
begin
for j:=1 to N do
if LT[j]=i then write(fo,j,' ');
writeln(fo);
end;
end;
BEGIN
assign(fi,tfi); reset(fi);
assign(fo,tfo); rewrite(fo);
Lê Thanh Bình 18
Docdl;
TimSLT;
Inkq;
close(fi); close(fo);
END.
6. Thuật toán sắp xếp topo các đỉnh của một đồ thị có hướng
không có chu trình (DAG)
Dữ liệu vào:
+Dòng đầu tiên ghi N là số đỉnh của đồ thị
+Các dòng tiếp theo, mỗi dòng ghi hai số u,v thể hiện có cạnh nối từ u đến v
Dữ liệu ra:
+Ghi trên 1 dòng dãy các đỉnh sau khi đã sắp xếp topo
Chương trình:
{$A+,B-,D+,E+,F-,G-,I+,L+,N+,O-,P-,Q+,R+,S+,T-,V+,X+
,Y+}
{$M 65520,0,655360}
uses crt;
const
tfi='INP.TXT';
tfo='OUT.TXT';
maxN=200;
var
fi,fo: text;
Gr: array[1..maxN,1..maxN] of byte;
N: integer;
TT: array[1..maxN] of integer;
CS: array[1..maxN] of integer;
sTT: integer;
procedure Docdl;
var u,v: integer;
begin
Fillchar(Gr,sizeof(Gr),0);
readln(fi,N);
while not seekeof(fi) do
begin
readln(fi,u,v);
Lê Thanh Bình 19
Gr[u,v]:=1;
end;
end;
procedure SxTopo;
var i: integer;
begin
Fillchar(TT,sizeof(TT),0);
Fillchar(CS,sizeof(CS),0);
sTT:=0;
for i:=1 to N do
if TT[i]=0 then
Loang(i);
end;
procedure Inkq;
var i: integer;
begin
for i:=1 to N do write(fo,CS[i],' ');
end;
BEGIN
assign(fi,tfi); reset(fi);
assign(fo,tfo); rewrite(fo);
Docdl;
SxTopo;
Inkq;
close(fi); close(fo);
END.
Lê Thanh Bình 20
Dữ liệu vào:
+Dòng đầu tiên ghi N là số đỉnh của đồ thị
+Dòng thứ hai ghi hai số xp, kt
+Các dòng tiếp theo, mỗi dòng chứa 3 số u,v,l thể hiện có cạnh nối u và v với
trọng số l
Dữ liệu ra:
+Dòng đầu tiên ghi tổng độ dài đường đi ngắn nhất từ xp đến kt
+Dòng thứ hai ghi số lượng các đỉnh trên đường đi
+Dòng thứ ba ghi danh sách các đỉnh trên đường đi ngắn nhất.
Chương trình:
{$A+,B-,D+,E+,F-,G-,I+,L+,N+,O-,P-,Q+,R+,S+,T-,V+,X+
,Y+}
{$M 65520,0,655360}
uses crt;
const
tfi='INP.TXT';
tfo='OUT.TXT';
maxN=100;
var
fi,fo: text;
N: integer;
xp,kt: integer;
Gr: array[1..maxN,1..maxN] of integer;
color: array[1..maxN] of integer;
kc: array[1..maxN] of integer;
tr: array[1..maxN] of integer;
Q: array[1..maxN] of integer;
qn: integer;
x: array[1..maxN] of integer;
slx: integer;
procedure InitQ;
begin
qn:=0;
end;
Lê Thanh Bình 21
procedure Docdl;
var i,j,u,v,l: integer;
begin
readln(fi,N);
readln(fi,xp,kt);
for i:=1 to N do
for j:=1 to N do Gr[i,j]:=-1;
while not seekeof(fi) do
begin
readln(fi,u,v,l);
Gr[u,v]:=l;
Gr[v,u]:=l;
end;
end;
procedure Dijstra;
var i,u,v: integer;
begin
for i:=1 to N do color[i]:=0;
InitQ;
Put(xp); color[xp]:=1; kc[xp]:=0; tr[xp]:=-1;
repeat
u:=Get; color[u]:=2;
for v:=1 to N do
Lê Thanh Bình 22
if (Gr[u,v]<>-1) then
begin
if (color[v]=1) and (kc[v]>kc[u]
+Gr[u,v]) then
begin
kc[v]:=kc[u]+Gr[u,v];
tr[v]:=u;
end;
if color[v]=0 then
begin
Put(v);
kc[v]:=kc[u]+Gr[u,v];
Tr[v]:=u;
color[v]:=1;
end;
end;
until Qempty or (color[kt]=2);
end;
procedure TimNguoc;
var u: integer;
begin
slx:=0;
if color[kt]<>2 then exit;
u:=kt;
repeat
inc(slx);
x[slx]:=u;
u:=tr[u];
until u=-1;
end;
procedure Inkq;
var i: integer;
begin
writeln(fo,kc[kt]);
writeln(fo,slx);
for i:=slx downto 1 do write(fo,x[i],' ');
end;
BEGIN
assign(fi,tfi); reset(fi);
assign(fo,tfo); rewrite(fo);
Docdl;
Lê Thanh Bình 23
Dijstra;
TimNguoc;
Inkq;
close(fi); close(fo);
END.
Có một số phiên bản của thủ tục dijstra cần phải lưu ý:
a.Dijstra chỉ sử dụng mảng Tr và kc (mảng Tr được dùng thay cho mảng
color)
procedure Dijstra;
var i,u,v: integer;
begin
for i:=1 to N do Tr[i]:=0;
InitQ;
Put(xp); kc[xp]:=0; tr[xp]:=-(N+1);
repeat
u:=Get; Tr[u]:=-Tr[u];
for v:=1 to N do
if (Gr[u,v]<>-1) then
begin
if (Tr[v]<0) and (kc[v]>kc[u]
+Gr[u,v]) then
begin
kc[v]:=kc[u]+Gr[u,v];
tr[v]:=-u;
end;
if Tr[v]=0 then
begin
Put(v);
kc[v]:=kc[u]+Gr[u,v];
Tr[v]:=-u;
end;
end;
until Qempty or (Tr[kt]>0);
end;
InitQ;
Put(xp); kc[xp]:=-Unseen;
repeat
u:=Get; kc[u]:=-kc[u];
if kc[u]=Unseen then kc[u]:=0;
for v:=1 to N do
if (Gr[u,v]<>-1) then
begin
if kc[v]<-(kc[u]+Gr[u,v]) then
begin
kc[v]:=-(kc[u]+Gr[u,v]);
if kc[v]=0 then kc[v]:=-Unseen;
end;
if kc[v]=Unseen then
begin
Put(v);
kc[v]:=-(kc[u]+Gr[u,v]);
if kc[v]=0 then kc[v]:=-Unseen;
end;
end;
until Qempty or (color[kt]=2);
end;
Dữ liệu vào:
+Dòng đầu tiên ghi N là số đỉnh của đồ thị
+Các dòng tiếp theo, mỗi dòng ghi 3 số u,v,l thể hiện có cạnh nối u và v với
trọng số l
Dữ liệu ra:
+Dòng đầu tiên ghi số S là tổng trọng số của cây khung
+N-1 dòng tiếp theo ghi các cạnh của cây khung
Chương trình:
{$A+,B-,D+,E+,F-,G-,I+,L+,N+,O-,P-,Q+,R+,S+,T-,V+,X+
,Y+}
{$M 65520,0,655360}
uses crt;
const
tfi='INP.TXT';
Lê Thanh Bình 25
tfo='OUT.TXT';
maxN=100;
var
fi,fo: text;
N: integer;
Gr: array[1..maxN,1..maxN] of integer;
Q: array[1..maxN] of integer;
color: array[1..maxN] of byte;
tr: array[1..maxN] of integer;
kc: array[1..maxN] of integer;
qn: integer;
procedure InitQ;
begin
qn:=0;
end;
procedure Put(u: integer);
begin
inc(qn);
q[qn]:=u;
end;
function Get: integer;
var u,i: integer;
begin
u:=1;
for i:=2 to qn do
if kc[q[i]]<kc[q[u]] then u:=i;
Get:=q[u];
q[u]:=q[qn];
dec(qn);
end;
function Qempty: boolean;
begin
Qempty:=(qn=0);
end;
procedure Docdl;
var i,j,u,v,l: integer;
begin
readln(fi,N);
for i:=1 to N do
for j:=1 to N do Gr[i,j]:=-1;
while not seekeof(fi) do
Lê Thanh Bình 26
begin
readln(fi,u,v,l);
Gr[u,v]:=l;
Gr[v,u]:=l;
end;
end;
procedure Prim;
var u,v: integer;
begin
InitQ;
Fillchar(color,sizeof(color),0);
Put(1); color[1]:=1; kc[1]:=0; tr[1]:=-1;
repeat
u:=Get; color[u]:=2;
for v:=1 to N do
if (Gr[u,v]<>-1) then
begin
if (color[v]=1) and (kc[v]>Gr[u,v])
then
begin
kc[v]:=Gr[u,v];
Tr[v]:=u;
end;
if color[v]=0 then
begin
Put(v);
color[v]:=1;
kc[v]:=Gr[u,v];
tr[v]:=u;
end;
end;
until Qempty;
end;
procedure Inkq;
var s,i: integer;
begin
s:=0;
for i:=2 to N do s:=s+kc[i];
writeln(fo,s);
for i:=2 to N do writeln(fo,i,' ',Tr[i]);
end;
Lê Thanh Bình 27
BEGIN
assign(fi,tfi); reset(fi);
assign(fo,tfo); rewrite(fo);
Docdl;
Prim;
Inkq;
close(fi); close(fo);
END.
Chú ý: Thủ tục Prim không sử dụng mảng color và mảng kc:
procedure Prim;
var u,v: integer;
begin
InitQ;
Put(1); tr[1]:=-(N+1);
repeat
u:=Get; Tr[u]:=-Tr[u];
for v:=1 to N do
if (Gr[u,v]<>-1) then
begin
if (Tr[v]<0) and (Gr[v,-
Tr[v]]>Gr[u,v]) then Tr[v]:=-u;
if Tr[v]=0 then
begin
Put(v);
tr[v]:=-u;
end;
end;
until Qempty;
end;
9. Thuật toán Kruskal tìm cây khung tối tiểu trên đồ thị được cho
bởi danh sách các cạnh
Dữ liệu vào:
+Dòng đầu tiên ghi N là số đỉnh của đồ thị
+Các dòng tiếp theo, mỗi dòng ghi 3 số nguyên u,v,l thể hiện có cạnh nối u và
v với tọng số l
Dữ liệu ra:
+Dòng đầu tiên ghi S là tổng giá trị của cây khung tối tiểu
+N-1 dòng tiếp theo, mỗi dòng ghi hai đỉnh là một cạnh của cây khung.
Lê Thanh Bình 28
Chương trình:
{$A+,B-,D+,E+,F-,G-,I+,L+,N+,O-,P-,Q+,R+,S+,T-,V+,X+
,Y+}
{$M 65520,0,655360}
uses crt;
const
tfi='INP.TXT';
tfo='OUT.TXT';
maxN=100;
maxM=10000;
var
fi,fo: text;
N: integer;
M: integer;
c: array[1..maxM,1..3] of integer;
dad: array[1..maxN] of integer;
x: array[1..maxN] of integer;
slx: integer;
procedure Docdl;
begin
readln(fi,N);
m:=0;
while not seekeof(fi) do
begin
inc(m);
readln(fi,c[m,1],c[m,2],c[m,3]);
end;
end;
begin
r:=c[(k+l) div 2,3];
i:=k; j:=l;
repeat
while c[i,3]<r do inc(i);
while c[j,3]>r do dec(j);
if i<=j then
begin
Doicho(c[i,1],c[j,1]);
Doicho(c[i,2],c[j,2]);
Doicho(c[i,3],c[j,3]);
inc(i); dec(j);
end;
until i>j;
if j>k then Qsort(k,j);
if i<l then Qsort(i,l);
end;
procedure Kruskal;
var i,u,v: integer;
begin
fillchar(dad,sizeof(dad),0);
slx:=0;
for i:=1 to M do
begin
u:=c[i,1]; v:=c[i,2];
while dad[u]<>0 do u:=dad[u];
while dad[v]<>0 do v:=dad[v];
if u<>v then
begin
inc(slx);
x[slx]:=i;
dad[u]:=v;
end;
end;
end;
procedure Inkq;
var S,i: integer;
begin
S:=0;
for i:=1 to slx do
S:=S+c[x[i],3];
writeln(fo,S);
Lê Thanh Bình 30
BEGIN
assign(fi,tfi); reset(fi);
assign(fo,tfo); rewrite(fo);
Docdl;
Qsort(1,M);
Kruskal;
Inkq;
close(fi); close(fo);
END.
10. Tìm đường đi ngắn nhất từ xp đến kt sử dụng thuật toán Floy-
Bellman
Dữ liệu vào:
+Dòng đầu tiên ghi N là số đỉnh của đồ thị
+Dòng thứ hai ghi hai số xp,kt
+Các dòng tiếp theo, mỗi dòng ghi 3 số u,v,l thể hiện có cạnh nối u và v với
trọng số l
Dữ liệu ra:
+Dòng đầu tiên ghi độ dài của đường đi ngắn nhất
+Dòng thứ hai ghi số lượng các đỉnh của đồ thị trên đường đi
+Dòng thứ 3 ghi danh sách các đỉnh trên đường đi
Chương trình:
{$A+,B-,D+,E+,F-,G-,I+,L+,N+,O-,P-,Q+,R+,S+,T-,V+,X+
,Y+}
{$M 65520,0,655360}
uses crt;
const
tfi='INP.TXT';
tfo='OUT.TXT';
maxN=50;
Unseen=1000000000;
var
fi,fo: text;
Lê Thanh Bình 31
N: integer;
Gr: array[1..maxN,1..maxN] of LongInt;
xp,kt: integer;
Tr: array[1..maxN,1..maxN] of integer;
x: array[1..maxN] of integer;
slx: integer;
procedure Docdl;
var i,j,u,v: integer;
l: LongInt;
begin
readln(fi,N);
for i:=1 to N do
for j:=1 to N do Gr[i,j]:=Unseen;
readln(fi,xp,kt);
while not seekeof(fi) do
begin
readln(fi,u,v,l);
Gr[u,v]:=l;
Gr[v,u]:=l;
end;
end;
procedure FloyBellman;
var i,j,k: integer;
begin
Fillchar(Tr,sizeof(Tr),0);
for k:=1 to N do
for i:=1 to N do
if i<>k then
for j:=1 to N do
if (i<>j) and (j<>k) then
if Gr[i,j]>Gr[i,k]+Gr[k,j] then
begin
Gr[i,j]:=Gr[i,k]+Gr[k,j];
Tr[i,j]:=k;
end;
end;
x[slx]:=u;
exit;
end;
Tim(u,Tr[u,v]);
Tim(Tr[u,v],v);
end;
procedure TimNguoc;
begin
slx:=0;
Tim(xp,kt);
inc(slx);
x[slx]:=kt;
end;
procedure Inkq;
var i: integer;
begin
writeln(fo,Gr[xp,kt]);
writeln(fo,slx);
for i:=1 to slx do write(fo,x[i],' ');
end;
BEGIN
assign(fi,tfi); reset(fi);
assign(fo,tfo); rewrite(fo);
Docdl;
FloyBellman;
TimNguoc;
Inkq;
close(fi); close(fo);
END.
11. Thuật toán tìm chu trình Euler trên đồ thị có chu trình Euler
(tất cả các đỉnh bậc chẵn)
Dữ liệu vào:
+Dòng đầu tiên ghi N là số đỉnh của đồ thị
+Các dòng tiếp theo, mỗi dòng ghi hai số u và v chỉ răng có thêm một cạnh
nối u và v
Dữ liệu ra: Ghi trên một dòng duy nhất số hiệu các đỉnh trên chu trình Euler
Chương trình:
Lê Thanh Bình 33
{$A+,B-,D+,E+,F-,G-,I+,L+,N+,O-,P-,Q+,R+,S+,T-,V+,X+
,Y+}
{$M 65520,0,655360}
uses crt;
const
tfi='INP.TXT';
tfo='OUT.TXT';
maxN=100;
maxM=10000;
var
fi,fo: text;
Gr: array[1..maxN,1..maxN] of integer;
N: integer;
x: array[1..maxM] of byte;
slx: integer;
S: array[1..maxM] of byte;
sn: integer;
procedure Docdl;
var u,v: integer;
begin
Fillchar(Gr,sizeof(Gr),0);
readln(fi,N);
while not seekeof(fi) do
begin
readln(fi,u,v);
Gr[u,v]:=Gr[u,v]+1;
Gr[v,u]:=Gr[v,u]+1;
end;
end;
procedure Euler;
var u,v: integer;
ke: boolean;
begin
slx:=0;
S[1]:=1; sn:=1;
repeat
u:=S[sn];
ke:=false;
Lê Thanh Bình 34
for v:=1 to N do
if Gr[u,v]>0 then
begin
ke:=true;
inc(sn);
S[sn]:=v;
Gr[u,v]:=Gr[u,v]-1;
Gr[v,u]:=Gr[v,u]-1;
break;
end;
if not ke then
begin
inc(slx);
x[slx]:=u;
dec(sn);
end;
until sn=0;
end;
procedure Inkq;
var i: integer;
begin
for i:=slx downto 1 do write(fo,x[i],' ');
end;
BEGIN
assign(fi,tfi); reset(fi);
assign(fo,tfo); rewrite(fo);
Docdl;
Euler;
Inkq;
close(fi); close(fo);
END.
Dữ liệu vào:
+Dòng đầu tiên ghi N là số đỉnh của đồ thị
+Trên các dòng tiếp theo, mỗi dòng ghi hai số u,v thể hiện có cạnh nối u và v
Chương trình:
Lê Thanh Bình 35
{$A+,B-,D+,E+,F-,G-,I+,L+,N+,O-,P-,Q+,R+,S+,T-,V+,X+
,Y+}
{$M 16384,0,655360}
uses crt;
const
tfi='INP.TXT';
tfo='OUT.TXT';
maxN=100;
var
fi,fo: text;
Gr: array[1..maxN,1..maxN] of byte;
N: integer;
ok: boolean;
dd: array[1..maxN] of byte;
x: array[1..maxN] of integer;
procedure Docdl;
var u,v: integer;
begin
Fillchar(Gr,sizeof(Gr),0);
readln(fi,N);
while not seekeof(fi) do
begin
readln(fi,u,v);
Gr[u,v]:=1;
Gr[v,u]:=1;
end;
end;
procedure ChuanBi;
begin
ok:=false;
fillchar(dd,sizeof(dd),0);
x[1]:=1; dd[1]:=1;
end;
procedure Inkq;
var i: integer;
begin
if not ok then
begin
writeln(fo,-1);
exit;
end;
for i:=1 to N do write(fo,x[i],' ');
writeln(fo,1);
end;
BEGIN
assign(fi,tfi); reset(fi);
assign(fo,tfo); rewrite(fo);
Docdl;
ChuanBi;
Thu(2);
Inkq;
close(fi); close(fo);
END.
Dữ liệu vào:
+Dòng đầu tiên ghi N là số đỉnh của đồ thị
+Các dòng tiếp theo, mỗi dòng ghi hai số nguyên u,v thể hiện có cạnh nối u
và v
Dữ liệu ra:
Lê Thanh Bình 37
Chương trình:
{$A+,B-,D+,E+,F-,G-,I+,L+,N+,O-,P-,Q+,R+,S+,T-,V+,X+
,Y+}
{$M 65520,0,655360}
uses crt;
const
tfi='INP.TXT';
tfo='OUT.TXT';
maxN=200;
var
fi,fo: text;
Gr: array[1..maxN,1..maxN] of byte;
N: integer;
color: array[1..maxN] of integer;
slm: integer;
count: integer;
procedure Docdl;
var u,v: integer;
begin
fillchar(Gr,sizeof(Gr),0);
readln(fi,N);
while not seekeof(fi) do
begin
readln(fi,u,v);
Gr[u,v]:=1;
Gr[v,u]:=1;
end;
end;
d:=0;
for j:=1 to N do
if (color[j]=0) and (Gr[i,j]=1) then
inc(d);
if d>max then
begin
max:=d;
u:=i;
end;
end;
end;
procedure Tomau;
var u,v: integer;
begin
Fillchar(color,sizeof(color),0);
slm:=0;
count:=0;
repeat
inc(slm);
TimDinhBacMax(u);
GanMau(u);
repeat
TimDinhCungMau(u,v);
if v>0 then
begin
GanMau(v);
NhapDinh(u,v);
end;
until v=0;
until count=N;
end;
procedure Inkq;
var i,j: integer;
Lê Thanh Bình 40
begin
writeln(fo,slm);
for i:=1 to slm do
begin
for j:=1 to N do
if color[j]=i then write(fo,j,' ');
writeln(fo);
end;
end;
BEGIN
assign(fi,tfi); reset(fi);
assign(fo,tfo); rewrite(fo);
Docdl;
ToMau;
Inkq;
close(fi); close(fo);
END.
Dữ liệu vào:
+Dòng đầu tiên ghi N là số đỉnh của đồ thị
+Các dòng tiếp theo, mỗi dòng ghi hai số u, v thể hiện có cạnh nối u và v
Dữ liệu ra:
+Dòng đầu tiên ghi S là số đỉnh trong tập ổn định trong cực đại
+Dòng thứ hai ghi S số nguyên là số hiệu của các đỉnh trong tập ổn định trong
cực đại.
Chương trình:
{$A+,B-,D+,E+,F-,G-,I+,L+,N+,O-,P-,Q+,R+,S+,T-,V+,X+
,Y+}
{$M 16384,0,655360}
uses crt;
const
tfi='INP.TXT';
tfo='OUT.TXT';
maxN=50;
maxS=4000;
Lê Thanh Bình 41
type
TapDinh=set of 1..maxN;
var
fi,fo: text;
Gr: array[1..maxN,1..2] of TapDinh;
N: integer;
solS: integer;
S,tam: array[1..maxS] of TapDinh;
procedure Docdl;
var i,u,v: integer;
begin
Fillchar(Gr,sizeof(Gr),0);
readln(fi,N);
for i:=1 to N do Gr[i,1]:=[i];
while not seekeof(fi) do
begin
readln(fi,u,v);
Include(Gr[u,2],v);
Include(Gr[v,2],u);
end;
end;
procedure TimTapOD;
var k,l,dem,i,j: integer;
th: TapDinh;
begin
solS:=2; S[1]:=Gr[1,1]; S[2]:=Gr[1,2];
for k:=2 to N do
begin
move(S,tam,sizeof(TapDinh)*solS);
dem:=0;
for i:=1 to solS do
for j:=1 to 2 do
begin
th:=tam[i]+Gr[k,j];
l:=1;
while (l<=dem) and (not
(S[l]<=th)) do inc(l);
if l>dem then
begin
l:=1;
while l<=dem do
Lê Thanh Bình 42
begin
while (l<=dem) and
(th<=S[l]) do
begin
S[l]:=S[dem];
dec(dem);
end;
inc(l);
end;
inc(dem);
S[dem]:=th;
end;
end;
solS:=dem;
end;
end;
procedure Inkq;
var min,i,j,d,imin: integer;
begin
min:=N+1;
for i:=1 to solS do
begin
d:=0;
for j:=1 to N do
if j in S[i] then inc(d);
if d<min then
begin
min:=d;
imin:=i;
end;
end;
writeln(fo,N-min);
for i:=1 to N do
if not (i in S[imin]) then write(fo,i,' ');
end;
BEGIN
assign(fi,tfi); reset(fi);
assign(fo,tfo); rewrite(fo);
Docdl;
TimTapOD;
Inkq;
close(fi); close(fo);
Lê Thanh Bình 43
END.
Dữ liệu vào:
+Dòng đầu tiên ghi N là số đỉnh của đồ thị
+Các dòng tiếp theo, mỗi dòng ghi hai số u,v thể hiện có cạnh nối u và v
Kết quả:
+Dòng đầu tiên ghi K là số đỉnh thuộc tập ổn định ngoài
+Dòng tiếp theo ghi K số nguyên là danh sách các đỉnh thuộc tập ổn định
ngoài
Chương trình:
{$A+,B-,D+,E+,F-,G-,I+,L+,N+,O-,P-,Q+,R+,S+,T-,V+,X+
,Y+}
{$M 65520,0,655360}
uses crt;
const
tfi='INP.TXT';
tfo='OUT.TXT';
maxN=100;
var
fi,fo: text;
Gr: array[1..maxN,0..maxN] of byte;
N: integer;
deg: array[1..maxN] of integer;
Min,M: integer;
xmin,x: array[1..maxN] of integer;
dd: array[1..maxN] of integer;
cx: array[1..maxN] of boolean;
procedure Docdl;
var u,v: integer;
begin
Fillchar(Gr,sizeof(Gr),0);
readln(fi,N);
while not seekeof(fi) do
begin
Lê Thanh Bình 44
readln(fi,u,v);
Gr[u,v]:=1;
Gr[v,u]:=1;
end;
for u:=1 to N do Gr[u,u]:=1;
end;
procedure ChuanBi;
var i,j: integer;
begin
Min:=N;
for i:=1 to N do xmin[i]:=i;
M:=0;
Fillchar(dd,sizeof(dd),0);
Fillchar(cx,sizeof(cx),true);
Fillchar(deg,sizeof(deg),0);
for i:=1 to N do
for j:=1 to N do
deg[i]:=deg[i]+Gr[i,j];
end;
procedure Inkq;
var i: integer;
begin
writeln(fo,Min);
for i:=1 to Min do write(fo,xmin[i],' ');
end;
BEGIN
assign(fi,tfi); reset(fi);
Lê Thanh Bình 46
assign(fo,tfo); rewrite(fo);
Docdl;
ChuanBi;
Thu(1);
Inkq;
close(fi); close(fo);
END.
16. Thuật toán Ford - Fulkerson tìm luồng cực đại trên mạng
Dữ liệu vào:
+Dòng đầu ghi N là số lượng đỉnh trong mạng
+Dòng thứ hai ghi 2 số xp, kt
+Các dòng tiếp theo, mỗi dòng ghi 3 số u,v,l thể hiện khả năng thông qua trên
cung (u,v) là l.
Dữ liệu ra:
+Dòng đầu tiên ghi giá trị của luồng cực đại
+N dòng kế tiếp ghi ma trận luồng cực đại.
Chương trình:
{$A+,B-,D+,E+,F-,G-,I+,L+,N+,O-,P-,Q+,R+,S+,T-,V+,X+
,Y+}
{$M 16384,0,655360}
uses crt;
const
tfi='INP.TXT';
tfo='OUT.TXT';
maxN=100;
Vocuc=30000;
var
fi,fo: text;
Gr: array[1..maxN,1..maxN] of Integer;
N: integer;
xp,kt: integer;
Fl: array[1..maxN,1..maxN] of integer;
mf: integer;
Q: array[1..maxN] of integer;
qf,ql: integer;
Tr: array[1..maxN] of integer;
EP: array[1..maxN] of integer;
Lê Thanh Bình 47
procedure InitQ;
begin
qf:=1;
ql:=1;
end;
procedure Put(u: integer);
begin
q[ql]:=u;
inc(ql);
end;
function Get: integer;
begin
Get:=q[qf];
inc(qf);
end;
function Qempty: boolean;
begin
Qempty:=(qf=ql);
end;
procedure Docdl;
var u,v: integer;
l: integer;
begin
Fillchar(Gr,sizeof(Gr),0);
readln(fi,N);
readln(fi,xp,kt);
while not seekeof(fi) do
begin
readln(fi,u,v,l);
Gr[u,v]:=l;
end;
end;
procedure InitFlow;
begin
Fillchar(Fl,sizeof(Fl),0);
end;
procedure IncFlow;
var d: integer;
u,v: integer;
begin
d:=EP[kt];
v:=kt;
repeat
u:=Tr[v];
if u<0 then
begin
u:=-u;
Fl[v,u]:=Fl[v,u]-d;
Lê Thanh Bình 49
end
else if u<N+1 then
Fl[u,v]:=Fl[u,v]+d;
v:=u;
until v=N+1;
end;
procedure MaxFlow;
var ok: boolean;
i: integer;
begin
InitFlow;
repeat
FindPath(ok);
if ok then IncFlow;
until not ok;
mf:=0;
for i:=1 to N do mf:=mf+Fl[xp,i];
end;
procedure Inkq;
var i,j: integer;
begin
writeln(fo,mf);
for i:=1 to N do
begin
for j:=1 to N do write(fo,Fl[i,j],' ');
writeln(fo);
end;
end;
BEGIN
assign(fi,tfi); reset(fi);
assign(fo,tfo); rewrite(fo);
Docdl;
MaxFlow;
Inkq;
close(fi); close(fo);
END.
17. Thuật toán tìm số cạnh ít nhất cần cắt bỏ khỏi đồ thị để từ xp
không thể đi đến được kt (thuật toán tìm lát cắt hẹp nhất)
Dữ liệu vào:
Lê Thanh Bình 50
Dữ liệu ra:
+Dòng đầu tiên ghi K là số cạnh tối thiểu cần loại bỏ
+K dòng tiếp theo, mỗi dòng ghi 2 số u, v thể hiện một cạnh bị bỏ
Chương trình:
{$A+,B-,D+,E+,F-,G-,I+,L+,N+,O-,P-,Q+,R+,S+,T-,V+,X+
,Y+}
{$M 16384,0,655360}
uses crt;
const
tfi='INP.TXT';
tfo='OUT.TXT';
maxN=100;
var
fi,fo: text;
Gr: array[1..maxN,1..maxN] of byte;
N: integer;
xp,kt: integer;
Fl: array[1..maxN,1..maxN] of byte;
mf: integer;
Q: array[1..maxN] of integer;
qf,ql: integer;
Tr: array[1..maxN] of integer;
procedure InitQ;
begin
qf:=1;
ql:=1;
end;
procedure Put(u: integer);
begin
q[ql]:=u;
inc(ql);
end;
function Get: integer;
begin
Lê Thanh Bình 51
Get:=q[qf];
inc(qf);
end;
function Qempty: boolean;
begin
Qempty:=(qf=ql);
end;
procedure Docdl;
var u,v: integer;
begin
Fillchar(Gr,sizeof(Gr),0);
readln(fi,N);
readln(fi,xp,kt);
while not seekeof(fi) do
begin
readln(fi,u,v);
Gr[u,v]:=1;
Gr[v,u]:=1;
end;
end;
procedure InitFlow;
begin
Fillchar(Fl,sizeof(Fl),0);
end;
end
else if Fl[v,u]=1 then
begin
Put(v);
Tr[v]:=-u;
end;
end;
until Qempty;
ok:=false;
end;
procedure IncFlow;
var u,v: integer;
begin
v:=kt;
repeat
u:=Tr[v];
if u<0 then
begin
u:=-u;
Fl[v,u]:=0;
end
else if u<N+1 then Fl[u,v]:=1;
v:=u;
until v=N+1;
end;
procedure MaxFlow;
var ok: boolean;
i: integer;
begin
InitFlow;
repeat
FindPath(ok);
if ok then IncFlow;
until not ok;
mf:=0;
for i:=1 to N do
mf:=mf+Fl[xp,i];
end;
procedure Inkq;
var i,j: integer;
begin
Lê Thanh Bình 53
writeln(fo,mf);
for i:=1 to N do if Tr[i]<>0 then
for j:=1 to N do if Tr[j]=0 then
if Gr[i,j]=1 then writeln(fo,i,' ',j);
end;
BEGIN
assign(fi,tfi); reset(fi);
assign(fo,tfo); rewrite(fo);
Docdl;
MaxFlow;
Inkq;
close(fi); close(fo);
END.
18. Thuật toán tìm cặp ghép trên đồ thị hai phía có số lượng cạnh
ghép là lớn nhất.
Dữ liệu vào:
+Dòng đầu ghi 2 số nguyên M, N là số đỉnh bên trái và bên phải
+M dòng tiếp theo, dòng thứ i ghi danh sách các đỉnh kề (bên phải) của đỉnh
bến trái i. Bắt đầu bằng số lượng đỉnh kề (k) và sau đó là danh sách các đỉnh
kề.
Dữ liệu ra:
+Dòng đầu tiên ghi S là số cạnh của cặp ghép
+S dòng tiếp theo, mô tả các cạnh của cặp ghép.
Chương trình:
{$A+,B-,D+,E+,F-,G-,I+,L+,N+,O-,P-,Q+,R+,S+,T-,V+,X+
,Y+}
{$M 16384,0,655360}
uses crt;
const
tfi='INP.TXT';
tfo='OUT.TXT';
maxN=100;
var
fi,fo: text;
Gr: array[1..maxN,1..maxN] of byte;
Lê Thanh Bình 54
M,N: integer;
Ft,Fp: array[1..maxN] of integer;
mf: integer;
Q: array[1..maxN] of integer;
qf,ql: integer;
Tr: array[1..maxN] of integer;
ktt,ktp: integer;
procedure InitQ;
begin
qf:=1;
ql:=1;
end;
procedure Put(u: integer);
begin
q[ql]:=u;
inc(ql);
end;
function Get: integer;
begin
Get:=q[qf];
inc(qf);
end;
function Qempty: boolean;
begin
Qempty:=(qf=ql);
end;
procedure Docdl;
var i,j,k,l: integer;
begin
Fillchar(Gr,sizeof(Gr),0);
readln(fi,M,N);
for i:=1 to M do
begin
read(fi,k);
for j:=1 to k do
begin
read(fi,l);
Gr[i,l]:=1;
end;
readln(fi);
end;
Lê Thanh Bình 55
end;
procedure InitFlow;
begin
Fillchar(Ft,sizeof(Ft),0);
Fillchar(Fp,sizeof(Fp),0);
end;
procedure IncFlow;
var u,v,v1: integer;
Lê Thanh Bình 56
begin
v:=ktp; u:=ktt;
repeat
v1:=Ft[u];
Ft[u]:=v;
Fp[v]:=u;
v:=v1;
u:=Tr[u];
until u=-1;
end;
procedure GhepMax;
var ok: boolean;
i: integer;
begin
InitFlow;
repeat
FindPath(ok);
if ok then IncFlow;
until not ok;
mf:=0;
for i:=1 to M do
if Ft[i]<>0 then inc(mf);
end;
procedure Inkq;
var i: integer;
begin
writeln(fo,mf);
for i:=1 to m do
if Ft[i]<>0 then
writeln(fo,i,' ',Ft[i]);
end;
BEGIN
assign(fi,tfi); reset(fi);
assign(fo,tfo); rewrite(fo);
Docdl;
GhepMax;
Inkq;
close(fi); close(fo);
END.
Lê Thanh Bình 57
19. Thuật toán tìm cặp ghép tối ưu đạt max trên đồ thị hai phía
Dữ liệu vào:
+Dòng đầu tiên ghi N là số lượng đỉnh ở bên trái (bên phải) của đồ thị
+N dòng tiếp theo mô tả ma trận trọng số của đồ thị hai phía
Dữ liệu ra:
+Dòng đầu tiên ghi S là tổng trọng số của cặp ghép
+N dòng tiếp theo mô tả các cạnh của cặp ghép
Chương trình:
{$A+,B-,D+,E+,F-,G-,I+,L+,N+,O-,P-,Q+,R+,S+,T-,V+,X+
,Y+}
{$M 16384,0,655360}
uses crt;
const
tfi='INP.TXT';
tfo='OUT.TXT';
maxN=100;
Vocuc=30000;
var
fi,fo: text;
c: array[1..maxN,1..maxN] of integer;
N: integer;
Nhan: array[1..2*maxN] of integer;
Ft,Fp: array[1..maxN] of integer;
Q: array[1..2*maxN] of integer;
qf,ql: integer;
Tr: array[1..2*maxN] of integer;
kt: integer;
Tong: integer;
procedure InitQ;
begin
qf:=1;
ql:=1;
end;
procedure Put(u: integer);
begin
q[ql]:=u;
Lê Thanh Bình 58
inc(ql);
end;
function Get: integer;
begin
Get:=q[qf];
inc(qf);
end;
function Qempty: boolean;
begin
Qempty:=(qf=ql);
end;
procedure Docdl;
var i,j: integer;
begin
Fillchar(c,sizeof(c),0);
readln(fi,N);
for i:=1 to N do
begin
for j:=1 to n do read(fi,c[i,j]);
readln(fi);
end;
end;
procedure KhoitaoNhan;
var i,j: integer;
begin
for i:=1 to N do
begin
nhan[i]:=c[i,1];
for j:=2 to N do
if Nhan[i]<c[i,j] then nhan[i]:=c[i,j]
end;
for i:=1 to N do Nhan[i+n]:=0;
end;
procedure KhoiTaoCapGhep;
begin
fillchar(Ft,sizeof(Ft),0);
fillchar(Fp,sizeof(Fp),0);
end;
begin
ok:=true;
InitQ;
fillchar(Tr,sizeof(Tr),0);
Put(xp); Tr[xp]:=2*N+1;
repeat
u:=Get;
if u<=N then
begin
for v:=1 to N do
if (c[u,v]=Nhan[u]+Nhan[v+n]) and
(Tr[v+n]=0) then
begin
Put(v+n);
Tr[v+n]:=u;
end;
end
else
begin
if Fp[u-N]=0 then
begin
kt:=u;
exit;
end;
v:=Fp[u-n];
if Tr[v]=0 then
begin
Put(v);
Tr[v]:=-u;
end;
end;
until Qempty;
ok:=false;
end;
procedure SuaNhan;
var dmin,i,j: integer;
begin
dmin:=Vocuc;
for i:=1 to N do if Tr[i]<>0 then
for j:=1 to N do if Tr[j+n]=0 then
if dmin>Nhan[i]+Nhan[j+n]-c[i,j] then
dmin:=Nhan[i]+Nhan[j+n]-c[i,j];
for i:=1 to N do if Tr[i]<>0 then
Lê Thanh Bình 60
Nhan[i]:=Nhan[i]-dmin;
for i:=1 to N do if Tr[i+n]<>0 then
Nhan[i+n]:=Nhan[i+n]+dmin;
end;
procedure TangCap;
var u,v: integer;
begin
v:=kt;
repeat
u:=Tr[v];
if u<0 then u:=-u
else if u<2*N+1 then
begin
Ft[u]:=v-n;
Fp[v-n]:=u;
end;
v:=u;
until v=2*N+1;
end;
procedure Ghep;
var i: integer;
ok: boolean;
begin
KhoiTaoNhan;
KhoiTaoCapGhep;
for i:=1 to N do
begin
repeat
TimDuong(i,ok);
if not ok then SuaNhan;
until ok;
TangCap;
end;
Tong:=0;
for i:=1 to N do
Tong:=Tong+c[i,Ft[i]];
end;
procedure Inkq;
var i: integer;
begin
writeln(fo,Tong);
Lê Thanh Bình 61
for i:=1 to N do
writeln(fo,i,' ',Ft[i]);
end;
BEGIN
assign(fi,tfi); reset(fi);
assign(fo,tfo); rewrite(fo);
Docdl;
Ghep;
Inkq;
close(fi); close(fo);
END.
Ghi chú: Để tìm cặp ghép tối ưu đạt min ta có thể thay hai thủ tục
KhoiTaoNhan và SuaNhan trong chương trình tìm cặp ghép tối ưu đạt
max bởi:
procedure KhoitaoNhan;
var i,j: integer;
begin
for i:=1 to N do Nhan[i]:=0;
for j:=1 to N do
begin
Nhan[j+n]:=c[1,j];
for i:=2 to N do
if c[i,j]<Nhan[j+n] then
Nhan[j+n]:=c[i,j];
end;
end;
procedure SuaNhan;
var dmin,i,j: integer;
begin
dmin:=Vocuc;
for i:=1 to N do if Tr[i]<>0 then
for j:=1 to N do if Tr[j+n]=0 then
if dmin>c[i,j]-Nhan[i]-Nhan[j+n] then
dmin:=c[i,j]-Nhan[i]-Nhan[j+n];
for i:=1 to N do if Tr[i]<>0 then
Nhan[i]:=Nhan[i]+dmin;
for i:=1 to N do if Tr[i+n]<>0 then
Nhan[i+n]:=Nhan[i+n]-dmin;
end;
Lê Thanh Bình 62
Dữ liệu vào:
+Dòng đầu tiên ghi 2 số nguyên dương N, M là số người và số lượng nhóm
Lê Thanh Bình 63
+N dòng tiếp theo, dòng thứ i mô tả danh sách các nhóm mục A mà người i
tham gia
+N dòng cuối, dòng thứ i mô tả danh sách các nhóm thuộc mục B mà người i
tham gia
Dữ liệu ra:
+Dòng đầu ghi S là số người đại diện tìm được
+S dòng tiếp theo, dòng thứ i ghi 3 số i, u, v thể hiện cho tên người, nhóm A
mà người đó làm đại diện, nhóm B mà người đó làm đại diện.
Chương trình:
{$A+,B-,D+,E+,F-,G-,I+,L+,N+,O-,P-,Q+,R+,S+,T-,V+,X+
,Y+}
{$M 16384,0,655360}
uses crt;
const
tfi='INP.TXT';
tfo='OUT.TXT';
maxN=100;
var
fi,fo: text;
Ga,Gb: array[1..maxN,1..maxN] of byte;
N,M: integer;
va,vb: array[1..maxN] of integer;
na,nb: array[1..maxN] of integer;
Q: array[1..4*maxN] of integer;
qf,ql: integer;
Tr: array[1..4*maxN] of integer;
kt: integer;
mf: integer;
procedure InitQ;
begin
qf:=1;
ql:=1;
end;
procedure Put(u: integer);
begin
q[ql]:=u;
inc(ql);
Lê Thanh Bình 64
end;
function Get: integer;
begin
Get:=q[qf];
inc(qf);
end;
function Qempty: boolean;
begin
Qempty:=(qf=ql);
end;
procedure Docdl;
var i,j,k,l: integer;
begin
Fillchar(Ga,sizeof(Ga),0);
Fillchar(Gb,sizeof(Gb),0);
readln(fi,N,M);
for i:=1 to N do
begin
read(fi,k);
for j:=1 to k do
begin
read(fi,l);
Ga[i,l]:=1;
end;
readln(fi);
end;
for i:=1 to N do
begin
read(fi,k);
for j:=1 to k do
begin
read(fi,l);
Gb[i,l]:=1;
end;
readln(fi);
end;
end;
procedure InitFlow;
begin
Fillchar(va,sizeof(va),0);
Fillchar(vb,sizeof(vb),0);
Fillchar(na,sizeof(na),0);
Lê Thanh Bình 65
Fillchar(nb,sizeof(nb),0);
end;
Put(v+m+2*n);
Tr[v+m+2*n]:=u;
end;
{nguoc}
if (na[u-(M+N)]<>0) and (Tr[u-N]=0) then
begin
Put(u-N);
Tr[u-N]:=-u;
end;
end;
kt:=u;
exit;
end;
Loaivb(u);
end;
end;
ok:=false;
end;
procedure IncFlow;
var u,v: integer;
begin
v:=kt;
repeat
u:=Tr[v];
if u<0 then u:=-u else
if u<2*(m+n)+1 then
begin
if u<=M then
begin
va[u]:=v-M;
na[v-M]:=u;
end
else if (u>m+n) and (u<=m+2*n) then
begin
nb[u-(m+n)]:=v-(m+2*n);
vb[v-(m+2*n)]:=u-(m+n);
end;
end;
v:=u;
until v=2*(m+n)+1;
end;
procedure Tim;
var ok: boolean;
i: integer;
begin
InitFlow;
repeat
FindPath(ok);
if ok then IncFlow;
until not ok;
mf:=0;
for i:=1 to M do
Lê Thanh Bình 68
procedure Inkq;
var i: integer;
begin
writeln(fo,mf);
for i:=1 to N do
if na[i]<>0 then
writeln(fo,i,' ',na[i],' ',nb[i]);
end;
BEGIN
assign(fi,tfi); reset(fi);
assign(fo,tfo); rewrite(fo);
Docdl;
Tim;
Inkq;
close(fi); close(fo);
END.
Lê Thanh Bình 69
Mục lục