马里奥
【问题描述】 马里奥将要参加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);
}