CodeVS 1002-搭桥

Posted HAdolf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CodeVS 1002-搭桥相关的知识,希望对你有一定的参考价值。

原题

题目描述 Description

有一矩形区域的城市中建筑了若干建筑物,如果某两个单元格有一个点相联系,则它们属于同一座建筑物。现在想在这些建筑物之间搭建一些桥梁,其中桥梁只能沿着矩形的方格的边沿搭建,如下图城市1有5栋建筑物,可以搭建4座桥将建筑物联系起来。城市2有两座建筑物,但不能搭建桥梁将它们连接。城市3只有一座建筑物,城市4有3座建筑物,可以搭建一座桥梁联系两栋建筑物,但不能与第三座建筑物联系在一起。

技术分享

输入描述 Input Description

在输入的数据中的第一行包含描述城市的两个整数r 和c, 分别代表从北到南、从东到西的城市大小(1 <= <= 50 and 1 <=  c <= 50). 接下来的r 行, 每一行由个(“#”)和(“.”)组成的字符. 每一个字符表示一个单元格。“#”表示建筑物,“.”表示空地。

 

输出描述 Output Description

在输出的数据中有两行,第一行表示建筑物的数目。第二行输出桥的数目和所有桥的总长度。

样例输入 Sample Input

样例1

3 5

#...#

..#..

#...#

 

样例2

3 5

##...

.....

....#

 

样例3

3 5

#.###

#.#.#

###.#

 

样例4:

3 5

#.#..

.....

....#

 

样例输出 Sample Output

样例1

5

4 4

 

样例2

2

0 0

 

样例3

1

0 0

 

样例4

3

1 1

 

题解

3000+B的码农题,这题一年前就开始在打了,可是当时一直调不过,就拖到了今天,我还是太弱了QwQ...

对于第一问,就是bfs求八个方向的连通块,bfs的同时再新建一个二维数组b,b[i][j]表示第[i][j]个位置的块属于哪一个连通块.

然后就是建图,这一步是最麻烦的.

枚举n*m个点,每个点再枚举9个方向:上右、上、上左、左上、左、左下、下左、下、下右、右下、右、右上.

如果遇到b[i][j]不同就建边,遇到b[i][j]相同则两点用并查集合在一起.

将图建出来之后就跑一遍最小生成树Kruskal{其实Prim也可以}.

将所有边按权值大小从小到大排,然后从最小的边开始枚举,如果两点已经在同一个集合的话就直接跳过,如果两点还没有在同一集合,就将两点所在的集合合并,并增加边数的答案以及权值之和的答案.

3892B Code:

 

 

const fx:array[1..8] of -1..1=(0,1,0,-1,-1,1,1,-1);
const fy:array[1..8] of -1..1=(1,0,-1,0,-1,1,-1,1);
var f:array[1..100000,1..2] of longint;
var c:array[1..1000,1..1000] of char;
var b:array[1..1000,1..1000] of longint;
var cost,x,y,fa:array[1..100000] of longint;
var i,j,n,m,ans1,ans2,ans3,k,t,tt,cnt:longint;
procedure qs(l,r:longint);//quicksort
var i,j,t,m:longint;
begin
  i:=l;j:=r;m:=cost[(l+r) div 2];
  repeat
    while cost[i]<m do inc(i);
    while cost[j]>m do dec(j);
    if i<=j then
    begin
      t:=cost[i];cost[i]:=cost[j];cost[j]:=t;
      t:=x[i];x[i]:=x[j];x[j]:=t;
      t:=y[i];y[i]:=y[j];y[j]:=t;
      inc(i);dec(j);
    end;
  until i>j;
  if i<r then qs(i,r);if l<j then qs(l,j);
end;
procedure bfs(x,y,k:longint);//求连通块
var i,j,front,nx,ny,p,rear:longint;
begin
  inc(ans1);
  front:=0;rear:=1;
  f[rear,1]:=x;f[rear,2]:=y;
  c[x,y]:=‘Z‘;b[x,y]:=k;//标记b数组
  while front<rear do
  begin
    inc(front);
    for i:=1 to 8 do
    begin
      nx:=f[front,1]+fx[i];
      ny:=f[front,2]+fy[i];
      if (nx>0)and(nx<=n)and(ny>0)and(ny<=m)and(c[nx,ny]=‘#‘) then
      begin
        inc(rear);
        f[rear,1]:=nx;f[rear,2]:=ny;
        b[nx,ny]:=k;c[nx,ny]:=‘Z‘;
      end;
    end;
  end;
end;
function v(x,y:longint):longint; begin exit((x-1)*m+y); end;
procedure build(x1,y1,x2,y2:longint);
begin
  inc(cnt);
  x[cnt]:=v(x1,y1);
  y[cnt]:=v(x2,y2);
  if abs(x1-x2)<=1 then cost[cnt]:=abs(y1-y2)-1 else
  if abs(y1-y2)<=1 then cost[cnt]:=abs(x1-x2)-1;
end;
function gf(x:longint):longint;
begin
  if fa[x]=x then gf:=x else
  fa[x]:=gf(fa[x]);gf:=fa[x];
end;
procedure merge(x,y:longint); begin x:=gf(x);y:=gf(y);fa[x]:=y; end;
begin
  readln(n,m);
  for i:=1 to n do
  begin
    for j:=1 to m do read(c[i,j]);
    readln;
  end;
  for i:=1 to n*m do fa[i]:=i;//初始化并查集数组
  for i:=1 to n do for j:=1 to m do if c[i,j]=‘#‘ then begin inc(k);bfs(i,j,k); end;
  for i:=1 to n do//建图
  for j:=1 to m do
  begin
    tt:=b[i,j];if tt=0 then continue;
    for k:=i+1 to n do
    begin
      if b[k,j]=tt then merge(v(i,j),v(k,j));
      if b[k,j-1]=tt then merge(v(i,j),v(k,j-1));
      if b[k,j+1]=tt then merge(v(i,j),v(k,j+1));
      if (b[k,j]<>tt)and(b[k,j]<>0) then build(i,j,k,j);
      if j-1>0 then if (b[k,j-1]<>tt)and(b[k,j-1]<>0) then build(i,j,k,j-1);
      if j+1<=m then if (b[k,j+1]<>tt)and(b[k,j+1]<>0) then build(i,j,k,j+1);
    end;
    for k:=i-1 downto 1 do
    begin
      if b[k,j]=tt then merge(v(i,j),v(k,j));
      if b[k,j-1]=tt then merge(v(i,j),v(k,j-1));
      if b[k,j+1]=tt then merge(v(i,j),v(k,j+1));
      if (b[k,j]<>tt)and(b[k,j]<>0) then build(i,j,k,j);
      if j-1>0 then if (b[k,j-1]<>tt)and(b[k,j-1]<>0) then build(i,j,k,j-1);
      if j+1<=m then if (b[k,j+1]<>tt)and(b[k,j+1]<>0) then build(i,j,k,j+1);
    end;
    for k:=j+1 to m do
    begin
      if b[i,k]=tt then merge(v(i,j),v(i,k));
      if b[i-1,k]=tt then merge(v(i,j),v(i-1,k));
      if b[i+1,k]=tt then merge(v(i,j),v(i+1,k));
      if (b[i,k]<>tt)and(b[i,k]<>0) then build(i,j,i,k);
      if i-1>0 then if (b[i-1,k]<>tt)and(b[i-1,k]<>0) then build(i,j,i-1,k);
      if i+1<=n then if (b[i+1,k]<>tt)and(b[i+1,k]<>0) then build(i,j,i+1,k);
    end;
    for k:=j-1 downto 1 do
    begin
      if (b[i,k]<>tt)and(b[i,k]<>0) then build(i,j,i,k) else if b[i,k]=tt then merge(v(i,j),v(i,k));
      if i-1>0 then if (b[i-1,k]<>tt)and(b[i-1,k]<>0) then build(i,j,i-1,k) else if b[i-1,k]=tt then merge(v(i,j),v(i-1,k));
      if i+1<=n then if (b[i+1,k]<>tt)and(b[i+1,k]<>0) then build(i,j,i+1,k) else if b[i+1,k]=tt then merge(v(i,j),v(i+1,k));
    end;
  end;
  qs(1,cnt);
  for i:=1 to cnt do//Kruskal
  begin
    if gf(x[i])=gf(y[i]) then continue else
    begin
      merge(x[i],y[i]);
      inc(ans3,cost[i]);
      inc(ans2);
    end;
  end;
  writeln(ans1);
  writeln(ans2,‘ ‘,ans3);
end.


测试点#brig0.in 结果: 内存使用量: 1260kB 时间使用量: 14ms 
测试点#brig1.in 结果: 内存使用量: 368kB 时间使用量: 2ms 
测试点#brig2.in 结果: 内存使用量: 492kB 时间使用量: 1ms 
测试点#brig3.in 结果: 内存使用量: 240kB 时间使用量: 1ms 
测试点#brig4.in 结果: 内存使用量: 496kB 时间使用量: 2ms 
测试点#brig5.in 结果: 内存使用量: 364kB 时间使用量: 1ms 
测试点#brig6.in 结果: 内存使用量: 364kB 时间使用量: 2ms 
测试点#brig7.in 结果: 内存使用量: 496kB 时间使用量: 1ms 
测试点#brig8.in 结果: 内存使用量: 752kB 时间使用量: 6ms 
测试点#brig9.in 结果: 内存使用量: 1008kB 时间使用量: 11ms 


欢迎转载,若转载请注明出处.

以上是关于CodeVS 1002-搭桥的主要内容,如果未能解决你的问题,请参考以下文章

CodeVS 1002-搭桥

codevs 1002 搭桥

codevs 1002 搭桥

搭桥(最小生成树)

并查集DFS搭桥

Code VS 1002 搭桥