You are on page 1of 69

Lê Thanh Bình 1

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

Chương trình 1: Dùng kỹ thuật đệ quy để duyệt chiều sâu:

{$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 Loang(u: integer);


var v: integer;
begin
LT[u]:=soLT;
for v:=1 to N do
if (Gr[u,v]=1) and (LT[v]=0) then
Loang(v);
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.

Chương trình 2: Sử dụng ngăn xếp tự tạo để duyệt chiều sâu:


{$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;
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;

procedure DuyetCS(xp: integer);


var u,v: integer;
Lê Thanh Bình 7

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.

Bài tập áp dụng

Bài 1: Nhà cao tầng


Một quần thể nhà cao tấng được xây dựng trên một nền hình chữ nhật, trên đó
được chia thành M x N ô vuông (M dòng, N cột, M, N≤ 100). Các dòng được
đánh số từ 1 đến M, các cột được đánh số từ 1 đến N. Người ta xem khu nhà
được tạo bởi các khối có đáy là một ô vuông với những chiều cao nào đó mà
người ta gọi là những đơn nguyên. Một đơn nguyên được xác định bởi toạ độ
dòng, cột của ô đáy và chiều cao tương ứng. Một khối nhà được định nghĩa là
một tập hợp các đơn nguyên có đáy tạo thành một miền gồm những ô vuông
kề cạnh. Người ta đánh số các khối nhà bằng các số nguyên liên tục bắt đầu từ
1 theo trình tự duyệt ô đáy theo từng dòng từ dòng 1 đến M và trên mỗi dòng
duyệt ô đáy theo từng cột từ 1 đến N.
Người ta muốn quét vôi các bức tường xung quanh tất cả các khối nhà. Hãy
xác định:
- Số lượng các khối nhà
- Tổng số diện tích quét vôi cho từng khối nhà
- Khối nhà có diện tích quét vôi lớn nhất và giá trị của diện tích này.
Dữ liệu: Vào từ file văn bản BUIL.INP với cấu trúc sau:
+Dòng đầu tiên ghi hai số M, N
+Mỗi dòng thứ i trong M dòng tiếp theo mỗi dòng ghi N số a[i,1], a[i,2],...,
a[i,n]. Mỗi số a[i,j] (1≤ i≤ M,1≤ j≤ N) tương ứng là một chiều cao của đơn
nguyên dòng i cột j với qui ước a[i,j]=0 khi đơn nguyên này không có. Giả
thiết rằng các giá trị này đều là những số nguyên và tính theo đơn vị một cạnh
ô vuông. Các số trên cùng một dòng ghi cách nhau ít nhất một dấu trắng.
Kết quả: Ghi ra file văn bản BUIL.OUT với cấu trúc như sau:
+Dòng đầu ghi số lượng các khối nhà (giả sử có k khối)
+Dòng thứ 2 ghi k số mỗi số là tổng diện tích quét vôi của khối nhà thứ i
(1≤ i≤ k)
+Dòng thứ 3 ghi 2 số: chỉ số của khối nhà có diện tích quét vôi lớn nhất và
diện tích này (các số trên cùng một dòng ghi cách nhau ít nhất một dấu trắng)
+Nếu không có khối nhà nào thì ghi số 0
Các giá trị diện tích được tính theo đơn vị diện tích một ô vuông.
Ví dụ:
BUIL.INP BUIL.OUT
3 5 4
1 1 0 2 2 8 16 20 16
0 1 0 0 1 3 20
Lê Thanh Bình 9

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

while not seekeof(fi) do


begin
readln(fi,u,v);
Gr[u,v]:=1;
end;
end;

procedure Lxuoi(u: integer);


var v: integer;
begin
TT[u]:=-1;
for v:=1 to N do
if (Gr[u,v]=1) and (TT[v]=0) then Lxuoi(v);
inc(sTT);
TT[u]:=sTT;
end;

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 Doicho(var u,v: integer);


var t: integer;
begin
t:=u;
u:=v;
v:=t;
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 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
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;

function TinhMin(u,v: integer): integer;


var min,w,m: integer;
begin
inc(sTT);
TT[v]:=sTT;
min:=TT[v];
for w:=1 to N do
if (Gr[v,w]=1) and (w<>u) then
begin
if TT[w]=0 then
begin
m:=TinhMin(v,w);
if m<min then min:=m;
if m>=TT[v] then BL[v]:=true;
end
else if min>TT[w] then min:=TT[w];
end;
pre[v]:=min;
TinhMin:=min;
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 Lxuoi(u: integer);


var v: integer;
begin
TT[u]:=-1;
for v:=1 to N do
if Gr[u,v]=1 then
begin
Gr[v,u]:=0; {dinh huong lai thanh mot
chieu}
if TT[v]=0 then Lxuoi(v);
end;
inc(sTT);
TT[u]:=sTT;
end;
Lê Thanh Bình 16

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 Doicho(var u,v: integer);


var t: integer;
begin
t:=u;
u:=v;
v:=t;
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 Loang(u: integer);


var v: integer;
begin
TT[u]:=-1;
for v:=1 to N do
if (Gr[u,v]=1) and (TT[v]=0) then Loang(v);
inc(sTT);
TT[u]:=sTT;
CS[n-sTT+1]:=u;
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

7. Thuật toán Dijstra tìm đường đi ngắn nhất từ xp đến kt trên đồ


thị có trọng số không âm

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 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);
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;

b.Dijtra chỉ dùng mảng kc


procedure Dijstra;
var i,u,v: integer;
begin
for i:=1 to N do kc[i]:=Unseen;
Lê Thanh Bình 24

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;

8. Thuật toán Prim để tìm cây khung tối tiể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 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;

procedure Doicho(var u,v: integer);


var t: integer;
begin
t:=u;
u:=v;
v:=t;
end;

procedure Qsort(k,l: integer);


var r,i,j: integer;
Lê Thanh Bình 29

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

for i:=1 to slx do


writeln(fo,c[x[i],1],' ',c[x[i],2]);
end;

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;

procedure Tim(u,v: integer);


begin
if Tr[u,v]=0 then
begin
inc(slx);
Lê Thanh Bình 32

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.

12. Tìm chu trình Haminton bằng duyệt quay lui

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

Dữ liệu ra: Thứ tự các đỉnh trên chu trình Haminton

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 Thu(k: integer);


var j: integer;
begin
if k>N then
begin
Lê Thanh Bình 36

if Gr[x[n],1]=1 then ok:=true;


exit;
end;
for j:=1 to N do
if (dd[j]=0) and (Gr[x[k-1],j]=1) then
begin
x[k]:=j;
dd[j]:=1;
Thu(k+1);
if ok then exit;
dd[j]:=0;
end;
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.

13. Thuật toán tô màu các đỉnh của đồ thị

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

+Dòng đầu ghi K là số màu cần dùng


+K dòng tiếp theo, mỗi dòng ghi danh sách các đỉnh của một màu

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;

procedure TimDinhBacMax(var u: integer);


var max,i,j,d: integer;
begin
max:=-1;
for i:=1 to N do
if color[i]=0 then
begin
Lê Thanh Bình 38

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 GanMau(u: integer);


begin
color[u]:=slm;
inc(count);
end;

procedure TimDinhCungMau(u: integer; var v:


integer);
var max,i,j,d: integer;
begin
v:=0; max:=0;
for i:=1 to N do
if (color[i]=0) and (Gr[u,i]=0) then
begin
d:=0;
for j:=1 to N do
if (color[j]=0) and (Gr[u,j]=1) and
(Gr[j,i]=1) then inc(d);
if d>max then
begin
max:=d;
v:=i;
end;
end;
if v>0 then exit;
max:=-1;
for i:=1 to N do
if (color[i]=0) and (Gr[u,i]=0) then
begin
d:=0;
for j:=1 to N do
Lê Thanh Bình 39

if (color[j]=0) and (Gr[i,j]=1) then


inc(d);
if d>max then
begin
max:=d;
v:=i;
end;
end;
end;

procedure NhapDinh(u,v: integer);


var i: integer;
begin
for i:=1 to N do
if Gr[v,i]=1 then
begin
Gr[u,i]:=1;
Gr[i,u]:=1;
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.

14. Thuật toán tìm tập ổn định trong cực đạ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 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.

15. Bài toán tìm tập ổn định ngoài cực tiể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 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 Thu(k: integer);


var inho,max,Nho,i,j,l: integer;
begin
Nho:=N;
inho:=0;
repeat
i:=0;
max:=0;
for j:=1 to N do
if cx[j] and (deg[j]>0) and (deg[j]>max)
and
((deg[j]<nho) or ((deg[j]=nho) and
(j>inho)))then
begin
max:=deg[j];
i:=j;
end;
if i>0 then
begin
x[k]:=i;
{ghi nhan trang thai}
cx[i]:=false;
for j:=1 to N do
Lê Thanh Bình 45

if (dd[j]=0) and (Gr[i,j]=1) then


begin
inc(M);
dd[j]:=k;
for l:=1 to N do
if cx[l] and (Gr[l,j]=1)
then dec(deg[l]);
end;
if M=N then
begin
if k<min then
begin
Min:=k;
xmin:=x;
end;
end
else if k<Min-1 then Thu(k+1);
{tra lai trang thai}
for j:=1 to N do
if dd[j]=k then
begin
dec(M);
dd[j]:=0;
for l:=1 to N do
if cx[l] and (Gr[l,j]=1)
then inc(deg[l]);
end;
cx[i]:=true;
end;
Nho:=max;
inho:=i;
until i=0;
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;

function min(u,v: integer): integer;


begin
if u<v then min:=u else min:=v;
end;
Lê Thanh Bình 48

procedure FindPath(var ok: boolean);


var u,v: integer;
begin
ok:=true;
InitQ;
Fillchar(Tr,sizeof(Tr),0);
Put(xp); Tr[xp]:=N+1; EP[xp]:=Vocuc;
repeat
u:=Get;
for v:=1 to N do
if Tr[v]=0 then
begin
if (Fl[u,v]<Gr[u,v]) then
begin
Put(v);
Tr[v]:=u;
EP[v]:=min(EP[u],Gr[u,v]-
Fl[u,v]);
if v=kt then exit;
end
else if Fl[v,u]>0 then
begin
Put(v);
Tr[v]:=-u;
EP[v]:=min(EP[u],Fl[v,u]);
end;
end;
until Qempty;
ok:=false;
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ò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 mỗi dòng ghi 2 số u,v thể hiện cho một cạnh của đồ thị.

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;

procedure FindPath(var ok: boolean);


var u,v: integer;
begin
ok:=true;
InitQ;
Fillchar(Tr,sizeof(Tr),0);
Put(xp); Tr[xp]:=N+1;
repeat
u:=Get;
for v:=1 to N do
if Tr[v]=0 then
begin
if (Gr[u,v]=1) and (Fl[u,v]=0) then
begin
Put(v);
Tr[v]:=u;
if v=kt then exit;
Lê Thanh Bình 52

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 FindPath(var ok: boolean);


var u,v,w: integer;
begin
ok:=true;
InitQ;
Fillchar(Tr,sizeof(Tr),0);
for u:=1 to M do
if Ft[u]=0 then
begin
Put(u);
Tr[u]:=-1;
end;
while not Qempty do
begin
u:=Get;
for v:=1 to N do
if (Gr[u,v]=1) and (Ft[u]<>v) then
begin
if Fp[v]=0 then
begin
ktt:=u; ktp:=v;
exit;
end;
w:=Fp[v];
if Tr[w]=0 then
begin
Put(w);
Tr[w]:=u;
end;
end;
end;
ok:=false;
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;

procedure TimDuong(xp: integer; var ok: boolean);


var u,v,w: integer;
Lê Thanh Bình 59

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

Bài tập áp dụng

Bài 1: Kế hoạch săn tin


Một toà soạn báo thể thao cần phân công n phóng viên (đánh số từ 1 đến
n), mỗi phóng viên đến một trong số n địa điểm khác nhau (cũng được đánh
số từ 1 đến n) để săn lùng tin về giải vô địch bóng đá. Mỗi phóng viên được
quyền đề xuất một danh sách gồm 3 địa điểm mà họ mong muốn đến công tác
xếp theo thứ tự ưa thích nhất, nhì, ba. Một cách phân công được gọi là chấp
nhận được là tất cả các phóng viên được đến ít nhất một địa điểm trong danh
sách 3 địa điểm mong ước. Nếu có cách phân công chấp nhận được, toà soạn
lại quan tâm đến cách phân công trong đó số phóng viên được đến địa điểm
họ ưa thích nhất là lớn nhất. Cách phân công như vậy gọi là cách phân công
phù hợp.
Yêu cầu: Nếu có cách phân công chấp nhận được, cần tìm cách phân
công phù hợp trong đó số phóng viên được cử đến địa điểm mà họ ưa thích
thứ nhì là lớn nhất. Ngược lại, cần đưa ra cách phân công mà trong đó số
phóng viên không được đến địa điểm nào trong danh sách 3 địa điểm ưa thích
của họ là nhỏ nhất.
Dữ liệu: Vào từ file văn bản ASSIGN.INP có cấu trúc như sau:
+Dòng đầu tiên chứa số nguyên dương n (n≤ 200)
+Dòng thứ i trong sóo n dòng tiếp theo chứa 3 số nguyên dương ai, bi, ci là
danh sách ba địa điểm ưa thích của phóng viên i (i=1,2,...,n)
Kết quả: Ghi ra file văn bản ASSIGN.OUT theo cấu trúc sau:
+Dòng đầu tiên ghi 3 số p, q, r trong đó p là số phóng viên không được đáp
ứng nguyện vọng, q là số phóng viên được cử đến địa điểm ưa thích nhất, r là
số phóng viên được cử đến địa điểm ưa thích thứ nhì trong cách phân công
tìm được.
+Dòng thứ i trong số n dòng tiếp theo ghi địa điểm mầ phóng viên i được cử
đến theo danh sách phân công tìm được.
Ví dụ:
ASSIGN.INP ASSIGN.OUT
6 0 1 1
1 2 3 1
1 2 3 2
1 2 3 3
2 3 4 4
4 5 6 6
3 4 5 5

20. Thuật toán tìm hệ đại diện phân biệt

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;

procedure Loaiva(u: integer);


var v: integer;
begin
for v:=1 to N do
if (Ga[v,u]=1) and (va[u]<>v) and (Tr[v+M]=0)
then
begin
Put(v+M);
Tr[v+M]:=u;
end;
end;

procedure Loaina(u: integer);


var v: integer;
begin
{xuoi}
if Tr[u+N]=0 then
begin
Put(u+N);
Tr[u+N]:=u;
end;
{nguoc}
if na[u-M]>0 then
begin
v:=na[u-M];
if Tr[v]=0 then
begin
Put(v);
Tr[v]:=-u;
end;
end;
end;

procedure Loainb(u: integer);


var v: integer;
begin
{xuoi}
for v:=1 to M do
if (Gb[u-(M+N),v]=1) and (nb[u-(M+N)]<>v) and
(Tr[v+m+2*n]=0) then
begin
Lê Thanh Bình 66

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;

procedure Loaivb(u: integer);


var v: integer;
begin
{nguoc}
v:=vb[u-(m+2*n)];
if (v<>0) and (Tr[v+m+n]=0) then
begin
Put(v+m+n);
Tr[v+m+n]:=-u;
end;
end;

procedure FindPath(var ok: boolean);


var u: integer;
begin
ok:=true;
InitQ;
Fillchar(Tr,sizeof(Tr),0);
for u:=1 to M do
if va[u]=0 then
begin
Put(u);
Tr[u]:=2*(M+N)+1;
end;
while not Qempty do
begin
u:=Get;
if u<=M then Loaiva(u) else
if u<=M+N then Loaina(u) else
if u<=M+2*N then Loainb(u) else
begin
if vb[u-(m+2*n)]=0 then
begin
Lê Thanh Bình 67

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

if va[i]<>0 then inc(mf);


end;

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

You might also like