连接格点 解题报告

来源:互联网 发布:汉语语法知乎 编辑:程序博客网 时间:2024/05/13 08:57

连接格点

时间限制1 Sec

内存限制128 MB

提交272

解决59

题目描述

      有一个MN列的点阵,相邻两点可以相连。一条纵向的连线花费一个单位,一条横向的连线花费两个单位。某些点之间已经有连线了,试问至少还需要花费多少个单位才能使所有的点全部连通。

输入

    第一行输入两个正整数m和n。(0<m,n<=1000)

   以下若干行每行四个正整数x1,y1,x2,y2,表示第x1行第y1列的点和第x2行第y2列的点已经有连线。输入保证|x1-x2|+|y1-y2|=1。

输出

输出使得连通所有点还需要的最小花费。

样例输入

2 2

1 1 2 1

样例输出

3

 

题目分析:

思考时应该思考到本题有两种特殊情况:

(1)   纵向全部相互连住

例如:

 (2)   横向全部相互连住

             

这两种情况应该举例子做特殊测试,尤其是贪心算法要小心m=n时的情况以及以上的两种情况。

(解①)最小生成树,并查集

题目为二维数组,用普通方法无法通过,所以考虑将二维转化为一维来处理,使用并查集。

代码:内存4280耗时131

vari,j,n,m,ans,x1,y1,x2,y2,x,y:longint;ij为计数变量,ans是数目

 b:array[0..1000000] of longint;{正确估计数据范围,若此句改为b:array0..100000of integer则只能通过百分之六十四}

functiondj(t:longint):longint;{并查集}

begin                                                             

if  t<>b[t]

then

b[t]:=dj(b[t]);

dj:=b[t];

end;

begin

 {assign(input,'???');文件名自拟

reset(input);

assign(output,'???');

rewrite(output);}

readln(m,n);

for i:=1to m*n do

 b[i]:=i;

ans:=0;

while noteof do

 begin

readln(x1,y1,x2,y2);

x:=dj((x1-1)*n+y1); {m*n的矩阵转成一维数组,共有m*n个元素,第ij列的元素转成一维对应于一位下标为(i-1)*n+j}

y:=dj((x2-1)*n+y2);

b[x]:=y;

 end;

for i:=1to n do{开始查看是否在同一集合}

for j:=1to m-1 do

 begin

x:=dj((j-1)*n+i);

y:=dj(j*n+i);

 if x<>y 先查找纵向

then

 begin

ans:=ans+1;

b[x]:=y;

 end;

注意:查找横向时加2

Ans:=ans+2;

纵向时加1

Ans:=ans+1;

 

 

end;

 for i:=1 to m do

for j:=1to n-1 do

begin

x:=dj((i-1)*n+j);

 y:=dj((i-1)*n+j+1);

 if x<>y then

begin

ans:=ans+2;//若不在同一集合则总数加二,并且将其合并

 b[x]:=y;

end;

end;

writeln(ans);

 //close(input);

 //close(output);

end.

(解②)搜索

DFS搜出整个点阵有几个部分,然后再检查是否有两个纵列的点之间完全没有水平线,若有则所求值+1,再加上点阵部分数就是最后结果了

另外:搜索部分如果用递归会栈溢出 改成模拟栈或用BFS实现就好了(我没有作此优化)

特别的,贪心法时间和内存均要较多的优化,比较复杂

代码(未优化,内存超限)可以通过百分之七十三  内存3236耗时60

programtest;

typearr=array[0..10000,0..10000]of boolean;{此句如果扩大范围的话可以将答案全部算对,但内存严重超限}

varm,n,x1,x2,y1,y2,i,j,k,s,t:integer;

    a,x,y:arr;

 

proceduredfs(i,j:integer;var a:arr);{简单的搜索}

begin

if a[i,j]then exit;

a[i,j]:=true;

ifx[i-1,j] then dfs(i-1,j,a);

ify[i,j-1] then dfs(i,j-1,a);

if x[i,j]then dfs(i+1,j,a);

if y[i,j]then dfs(i,j+1,a);

end;

 

begin

{assign(input,'test.in');

reset(input);}

readln(m,n);

repeat

readln(x1,y1,x2,y2);

ifx1-x2=1 then x[x2,y1]:=true

else ifx2-x1=1 then x[x1,y1]:=true

else ify1-y2=1 then y[x1,y2]:=true

elsey[x1,y1]:=true;

untileof;

搜出整个点阵有几个部分之后,再检查是否有两个纵列的点之间完全没有水平线,

 

close(input);

for i:=1to m do

for j:=1to n do

if nota[i,j] then begin dfs(i,j,a);inc(s);end;

for i:=1to n-1 do

begin

k:=0;

for j:=1to m do if y[i,j] then begin k:=1;break;end;

if k=0then inc(t);

end;

//assign(output,'test.out');

//rewrite(output);

writeln(s+t-1);

//close(output);

end.

解题心得:

只有认真分析题目模型才能完全解决问题

0 0
原创粉丝点击