国庆七天测(五)马里奥

版权声明:写得不好,随便转载,但请注明出处,感激不尽 https://blog.csdn.net/xyc1719/article/details/82944327

【一句话题意】给一个图,有一些可以空岛可以落脚。左右相邻的空岛之间移动不需要梯子,在同一列的空岛之间上下移动需要长度大于等于高度差的梯子。问从起点到终点至少需要多长的梯子。

【算法一】鉴于拥有固定长度的梯子,跑一遍bfs确定是否可行的复杂度是O(n)的,且答案关于梯子长度单调。我们可以二分答案,二分梯子的长度再check。总复杂度为O(nlogn)
【算法二】格子图的求到某个点的最小值,一般可以用各种的spfa变种完成。总复杂度O(玄学)
【算法三】把所有空岛连边,跑最小生成树。每加进一条边就检查起点、终点是否在同一集合。注意上下只加相邻的空岛。总复杂度O(nlogn)

给出算法三代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rint register int
using namespace std;
const int maxn=1051;
int n,m,tot;
bool g[maxn][maxn];
char s[maxn];
struct Edge{
	int u,v,c;
}edge[maxn*maxn];
int f[maxn*maxn];
bool cmp(Edge x,Edge y){
	return x.c<y.c;
}
inline int find(int x){if(f[x]!=x)f[x]=find(f[x]);return f[x];}
int main(){
	freopen("mario.in","r",stdin);
	freopen("mario.out","w",stdout);
	cin>>n>>m;
	for(rint i=1;i<=n;i++){
		scanf("%s",s);
		for(rint j=0;j<m;j++)
		if(s[j]=='_')g[i][j+1]=0;
		else g[i][j+1]=1;
	}
	int x,y,e1,e2;
	cin>>x>>y;e1=(n-1)*m+1,e2=(x-1)*m+y;
	for(rint i=1;i<=n*m;i++)f[i]=i;
	for(rint i=1;i<=n;i++)
		for(rint j=1;j<m;j++)
			if(g[i][j]&&g[i][j+1])edge[++tot]=(Edge){(i-1)*m+j,(i-1)*m+j+1,0};
	for(rint j=1;j<=m;j++){
		rint p1=1,p2;
		while(p1<=n&&!g[p1][j])	p1++;
		p2=p1+1;
		while(p2<=n){
			if(g[p2][j])edge[++tot]=(Edge){(p1-1)*m+j,(p2-1)*m+j,p2-p1},p1=p2;
			p2++;
		}
	}
	sort(edge+1,edge+tot+1,cmp);
	for(rint i=1;i<=tot;i++){
		f[find(edge[i].u)]=find(edge[i].v);
		if(find(e1)==find(e2)){
			printf("%d\n",edge[i].c);
			return 0;
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/xyc1719/article/details/82944327
今日推荐