馬里奧
【問題描述】 馬里奧將要參加NOIP了,他現在在一片大陸上,這個大陸上有着許多浮空島,並且其中一座浮空島上有一個傳送門,馬里奧想要到達傳送門從而前往NOIP的考場。從一座浮空島出發,馬里奧可以到達一個在水平方向和這個浮空島相接的另一個浮空島,他還可以使用梯子到達在這個浮空島正上方或正下方的另一座浮空島,但是這兩個浮空島的高度差不能超過梯子的長度。現在,馬里奧希望用最短的梯子到達傳送門,請你輸出梯子的最短長度。 我們把浮空島抽象成一個二維平面,’#’代表浮空島,’_’代表空中。兩個整數x,y代表傳送門所在的行數和列數。保證最下方一行全部爲’#’,且傳送門所在位置爲’#’,馬里奧一開始在最左下方的那個浮空島上。
【輸入格式】 第一行兩個整數n,m,表示輸入平面的行數和列數。 接下來n行每行一個包含m個字符的字符串,表示這個二維平面。 最後一行兩個整數x,y表示傳送門所在的行和列。
【輸出格式】 輸出一行一個整數,表示梯子的最小長度。
這道題……仔細想想是可以發現可以做最小生成樹的,我把所有相鄰的點連接在一起,水平的邊賦值爲0,垂直的邊則爲高度,那麼我們一開始肯定是把相鄰的邊連在一起,那麼當起點和終點同一個父親的時候,那麼之前進來所有邊的最大邊,肯定就是答案。
證明很好證的……比它大的邊肯定不會進來,而且非零的邊無論是什麼肯定都在裏面,那麼就對了
#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
char a[maxn][maxn];
int fa[maxn*maxn],n,m,cnt,num,ans,zhong,qi,vis[maxn*maxn];
inline int find(int x)
{
if (x==fa[x]) return fa[x];
return fa[x]=find(fa[x]);
}
struct node
{
int u,v,w;
}e[2000010];
bool cmp(node x,node y)
{
return x.w<y.w;
}
inline void add(int u,int v,int w)
{
cnt++;
e[cnt].u=u;
e[cnt].v=v;
e[cnt].w=w;
}
inline void build()
{
for (int i=1; i<=n; i++)
{
int j=1;
while (j<=m)
{
if (a[i][j+1]=='#'&&a[i][j]=='#')
{
//cout<<(i-1)*m+j<<" "<<(i-1)*m+j+1<<endl;
add((i-1)*m+j,(i-1)*m+j+1,0);
add((i-1)*m+j+1,(i-1)*m+j,0);
j++;
}
else j++;
}
}
for (int j=1; j<=m; j++)
{
//cout<<j<<endl;
int fi=1,i=1;
while (a[i][j]!='#')
i++;
fi=i;
while (i<=n)
{
i++;
if (a[i][j]=='#'&&a[fi][j]=='#')
{
add((fi-1)*m+j,(i-1)*m+j,i-fi);
add((i-1)*m+j,(fi-1)*m+j,i-fi);
fi=i;
}
}
}
}
inline void kruscal()
{
for (int i=1; i<=cnt; i++)
{
int u=e[i].u,v=e[i].v;
int fu=find(u),fv=find(v);
if (fu!=fv)
{
//cout<<u<<' '<<v<<endl;
//if (num==1) return;
fa[fu]=fv;
ans=max(ans,e[i].w);
if (find(qi)==find(zhong)) return;
//num--;
}
}
}
int main()
{
freopen("mario.in","r",stdin);
freopen("mario.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++)
{
cin>>a[i][j];
fa[(i-1)*n+j]=(i-1)*n+j;
}
qi=(n-1)*m+1;
int o,q;
scanf("%d%d",&o,&q);
zhong=(o-1)*m+q;;
build();
sort(e+1,e+cnt+1,cmp);
kruscal();
printf("%d",ans);
}