这道题,乍一看,大家会想到那个记忆化搜索的“滑雪”,但是,这两道题是完全不同的。这题题意有些难以理解:给出一块滑雪场的地形图,只能由一个点向相邻的点去滑,而且低处不能滑向高处。缆车是可以安装在任意两点间的,每个点也可以安装多部缆车,缆车可以使连接的两个相通。求最少的缆车数目使得所有格子之间都互相联通。
怎么做呢?强联通分量嘛!
Tarjan是伟大的,以Tarjan冠名的算法主要有三个:求LCA的Tarjan算法,求割点、割边的Tarjan算法以及求强连通分量的Tarjan算法。本题所采用的就是Tarjan算法求强连通分量。其实,由于本题的特殊性,也可以用Floodfill来求强连通分量,但是Tarjan算法显然更为普遍,具有普适性。
具体说说这题的过程:
1、读入并建图,如果这点的高度不比相邻点高度低,那么就从此点向相邻点连一条有向边
2、Tarjan算法求出所有的强连通分量。给出伪代码(c++语言的同学不要笑我啊):
Void Tarjan(int i);
{
time<-time+1;
dfn[i]<-time;low[i]<-time;
将i的入栈标记记为true
for (j=last[i],j<>0,j=pre[j])
{
k=other[j];
if (k在栈中)
{if (dfn[k]<low[i]) low[i]=dfn[k]}
else if(k未被访问过)
{
Tarjan(k);
if (low[k]<low[i]) low[i]=low[k];
}
}
if (low[i]==dfn[i]) Deal(i);//Deal的含义是处理出所有与i同属一个强连通分量的点
}
3、对于每个强连通分量进行处理,累加每个强连通分量的入度和出度。
4、统计入度和出度为0的强连通分量的个数,选择大的输出(这个可以证明,请各位同学自己完成证明)
CODE
{$M 100000000}
Program POJ2375;//By_Poetshy
Const
maxn=250005;
ddx:Array[1..4]of Integer=(0,0,1,-1);
ddy:Array[1..4]of Integer=(-1,1,0,0);
Var
i,j,k,m,n,p,q,l,time,sum,all :Longint;
color,pre,other,last,stack,into,outo,dfn,low :Array[0..maxn*10]of Longint;
a :Array[0..505,0..505]of Longint;
had :Array[0..505,0..505]of Boolean;
v :Array[0..maxn]of Boolean;
Procedure Deal(i:Longint);
var j,k:Longint;
begin
inc(all);
while i<>stack[sum]do
begin
v[stack[sum]]:=false;
color[stack[sum]]:=all;
dec(sum);
end;
color[i]:=all;
dec(sum);
v[i]:=false;
end;
Procedure Tarjan(i:Longint);
var j,k:Longint;
begin
inc(time);inc(sum);stack[sum]:=i;
dfn[i]:=time;low[i]:=time;
j:=last[i];v[i]:=true;
while j<>0 do
begin
k:=other[j];
if dfn[k]=-1 then
begin
Tarjan(k);
if low[i]>low[k] then low[i]:=low[k];
end else if v[k] then if dfn[k]<low[i] then low[i]:=dfn[k];
j:=pre[j];
end;
if low[i]=dfn[i] then Deal(i);
end;
BEGIN
readln(n,m);k:=0;time:=0;
fillchar(last,sizeof(last),0);
fillchar(into,sizeof(into),0);
fillchar(outo,sizeof(outo),0);
fillchar(v,sizeof(v),0);
for i:=1 to m do
for j:=1 to n do
read(a[i,j]);
for i:=1 to m do
for j:=1 to n do
begin
q:=(i-1)*n+j;
for p:=1 to 4 do
if (ddx[p]+i>0)and(ddy[p]+j>0)and(ddx[p]+i<=m)and(ddy[p]+j<=n)then
if a[i,j]>=a[i+ddx[p],j+ddy[p]] then
begin
inc(k);l:=(i+ddx[p]-1)*n+j+ddy[p];
pre[k]:=last[q];last[q]:=k;other[k]:=l;
end;
end;
fillchar(dfn,sizeof(dfn),255);
for i:=1 to n*m do if dfn[i]=-1 then Tarjan(i);
if all=1 then
begin
writeln(0);
halt;
end;
for i:=1 to n*m do
begin
j:=last[i];
while j<>0 do
begin
k:=other[j];
if color[i]<>color[k] then
begin
inc(into[color[k]]);
inc(outo[color[i]]);
end;
j:=pre[j];
end;
end;
p:=0;q:=0;
for i:=1 to all do
begin
if outo[i]=0 then inc(q);
if into[i]=0 then inc(p);
end;
if p>q then writeln(p) else writeln(q);
END.
本文探讨了一种使用Tarjan算法解决滑雪场缆车安装问题的方法,通过构建图并应用Tarjan算法求出强连通分量,最终得出最少缆车数量以实现滑雪场所有区域联通。此外,还提供了详细的算法实现步骤和代码片段。
589

被折叠的 条评论
为什么被折叠?



