连接格点
时间限制: 1 Sec
内存限制: 128 MB
提交: 272
解决: 59
题目描述
有一个M行N列的点阵,相邻两点可以相连。一条纵向的连线花费一个单位,一条横向的连线花费两个单位。某些点之间已经有连线了,试问至少还需要花费多少个单位才能使所有的点全部连通。
输入
第一行输入两个正整数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;i,j为计数变量,ans是数目
b:array[0..1000000] of longint;{正确估计数据范围,若此句改为b:array【0..100000】of 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个元素,第i行j列的元素转成一维对应于一位下标为(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;
|
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.
解题心得:
只有认真分析题目模型才能完全解决问题