Nguồn đề bài: http://vn.spoj.com/problems/FWATER/
1. Đề bài FWATER spoj
Nông dân John quyết định mang nước tới cho N (1 <= N <= 300) đồng cỏ của mình, để thuận tiện ta đánh số các đồng cỏ từ 1 đến N. Để tưới nước cho 1 đồng cỏ John có thể chọn 2 cách, 1 là đào ở đồng cỏ đó 1 cái giếng hoặc lắp ống nối dẫn nước từ những đồng cỏ trước đó đã có nước tới.
Để đào một cái giếng ở đồng cỏ i cần 1 số tiền là W_i (1 <= W_i <= 100,000). Lắp ống dẫn nước nối 2 đồng cỏ i và j cần 1 số tiền là P_ij (1 <= P_ij <= 100,000; P_ij = P_ji; P_ii=0).
Tính xem nông dân John phải chi ít nhất bao nhiêu tiền để tất cả các đồng cỏ đều có nước.
DỮ LIỆU
- Dòng 1: Một số nguyên duy nhất: N
- Các dòng 2..N + 1: Dòng i+1 chứa 1 số nguyên duy nhất: W_i
- Các dòng N+2..2N+1: Dòng N+1+i chứa N số nguyên cách nhau bởi dấu cách; số thứ j là P_ij
KẾT QUẢ
- Dòng 1: Một số nguyên duy nhất là chi phí tối thiểu để cung cấp nước cho tất cả các đồng cỏ.
VÍ DỤ
Dữ liệu
4
5
4
4
3
0 2 2 2
2 0 3 3
2 3 0 4
2 3 4 0
Kết quả
9
2. Giải thích FWATER spoj
Có 4 đồng cỏ. Mất 5 tiền để đào 1 cái giếng ở đồng cỏ 1, 4 tiền để đào ở đồng cỏ 2, 3 và 3 tiền để đào ở đồng cỏ 4. Các ống dẫn nước tốn 2, 3, và 4 tiền tùy thuộc vào nó nối đồng cỏ nào với nhau.
Nông dân John có thể đào 1 cái giếng ở đồng cỏ thứ 4 và lắp ống dẫn nối đồng cỏ 1 với tất cả 3 đồng cỏ còn lại, chi phí tổng cộng là 3 + 2 + 2 + 2 = 9.
3. Hướng dẫn FWATER spoj
– Xây dựng thêm 1 đỉnh N+1 có cạnh nối với i (i=1..n) chính là chi phí của giếng nước thứ i.
– Sau đó tìm cây khung có trọng số nhỏ nhất. ở đây có thể dùng Prim hoặc Kruskal đều được.
4. Code tham khảo FWATER spoj
const fi='FWATER.inp';
nmax=301;
type data=longint;
dulieu=record
u,v,c:data;
end;
var
f:text;
B:array[1..300*300] of dulieu;
A:array[0..nmax+1,0..nmax+1] of data;
n,m:data;
root:array[0..nmax+1] of data;
procedure docfile;
var i,j,u,v,c:data;
begin
assign(f,fi); reset(f);
readln(f,n);
fillchar(a,sizeof(a),0);
for i:=1 to n do
begin
readln(f,c);
a[n+1,i]:=c;
a[i,n+1]:=c;
end;
for i:=1 to n do
for j:=1 to n do
read(f,a[i,j]);
n:=n+1;
m:=0;
for i:=1 to n-1 do
for j:=i+1 to n do
begin
inc(m);
with b[m] do
begin
u:=i;
v:=j;
c:=a[i,j];
end;
end;
close(f);
end;
procedure sort(l,r: longint);
var
x,i,j: longint;
y:dulieu;
begin
i:=l;
j:=r;
x:=b[(l+r) div 2].c;
repeat
while b[i].c<x do inc(i);
while x<b[j].c do dec(j);
if not(i>j) then
begin
y:=b[i];
b[i]:=b[j];
b[j]:=y;
inc(i);
j:=j-1;
end;
until i>j;
if l<j then
sort(l,j);
if i<r then
sort(i,r);
end;
procedure union(a,b:data);
begin
root[a]:=b;
end;
function findroot(x:data):data;
begin
if root[x]<>x then
root[x]:=findroot(root[x]);
exit(root[x]);
end;
procedure kruskal;
var i,j,u,v,res:data;
begin
for i:=1 to n do
root[i]:=i;
res:=0;
for i:=1 to m do
begin
u:=findroot(b[i].u);
v:=findroot(b[i].v);
if u<>v then
begin
union(u,v);
res:=res+b[i].c;
end;
end;
writeln(res);
end;
begin
docfile;
sort(1,m);
kruskal;
readln;
end.