清扫
时间限制: 1 Sec 内存限制: 128 MB
题目描述
现在要打扫国王的牧圈。已经30年没打扫了。所以这次的计划是用河水来冲。
牧圈排成整齐的格子,每相邻的两个之间都有门。要想让水进去,就必须打开这些门。这不是件容易的事情。因为有些圈里土堆得很高。因此打开门就很费劲。为了使花的力气最小,总是把门推向土低的一边。你的任务是计算最少得费多少劲。我们用土的厚度来描述这个值。
输入
第一行是宽度w和高度h,其中3 <= w,h <= 40。以下h行数据,描述了土的高度,也就是我们所浪费体力的度量。数据的范围在1到100之间。
输出
你得到的结果。所有的格子都必须进水。水是从左上角的格子进去的。
样例输入
4 3
3 5 2 1
7 3 4 8
1 6 5 7
样例输出
26
题解
给出了各个点的土堆高度,可以得出相邻两个点间的花费,即分w[i,j]=min(x[i],x[j])
然后Prim/Kruskal随便搞了
Kruskal版本
var
rank,father:array[0..1600]of longint;
edge:array[0..4950,1..3]of longint;
w:array[1..40,1..40]of longint;
i,j,k,l:longint;
n,m,ans:longint;
a,b,c,d:longint;
procedure sort(l,r: longint);
var i,j,k,x,y: longint;
begin
i:=l; j:=r; x:=edge[(l+r) div 2,3];
repeat
while edge[i,3]<x do inc(i);
while x<edge[j,3] do dec(j);
if not(i>j)
then
begin
for k:=1 to 3 do
begin y:=edge[i,k]; edge[i,k]:=edge[j,k]; edge[j,k]:=y; end;
inc(i); dec(j);
end;
until i>j;
if l<j then sort(l,j);
if i<r then sort(i,r);
end;
function getfather(a:longint):longint;
begin
if father[a]=a
then exit(a);
father[a]:=getfather(father[a]);
exit(father[a]);
end;
procedure union(a,b:longint);
var x,y,tt:longint;
begin
x:=getfather(a);
y:=getfather(b);
tt:=rank[x]+rank[y];
if rank[x]>rank[y]
then begin rank[x]:=tt; rank[y]:=rank[x]; father[y]:=x; getfather(b); end
else begin rank[y]:=tt; rank[x]:=rank[y]; father[x]:=y; getfather(a); end;
end;
function min(a,b:longint):longint;
begin
if a>b
then exit(b)
else exit(a);
end;
begin
readln(n,m);
for i:=1 to m do
begin
for j:=1 to n do
read(w[i,j]);
readln;
end;
for i:=1 to m do
for j:=1 to n do
begin
k:=1; l:=0;
if (i+k>0)and(i+k<=m)and(j+l>0)and(j+l<=n)
then
begin
inc(edge[0,1]);
edge[edge[0,1],1]:=(i+k-1)*n+j+l;
edge[edge[0,1],2]:=(i-1)*n+j;
edge[edge[0,1],3]:=min(w[i,j],w[i+k,j+l]);
end;
k:=0; l:=1;
if (i+k>0)and(i+k<=m)and(j+l>0)and(j+l<=n)
then
begin
inc(edge[0,1]);
edge[edge[0,1],1]:=(i+k-1)*n+j+l;
edge[edge[0,1],2]:=(i-1)*n+j;
edge[edge[0,1],3]:=min(w[i,j],w[i+k,j+l]);
end;
end;
sort(1,edge[0,1]);
for i:=1 to edge[0,1] do
begin
if edge[i,1]>edge[i,2]
then begin d:=edge[i,1]; edge[i,1]:=edge[i,2]; edge[i,2]:=d; end;
end;
for i:=1 to n*m do
begin
father[i]:=i;
rank[i]:=1;
end;
for i:=1 to edge[0,1] do
begin
if getfather(edge[i,1])<>getfather(edge[i,2])
then
begin
union(edge[i,1],edge[i,2]);
inc(ans,edge[i,3]);
end;
end;
writeln(ans);
end.