科大讯飞杯 迷宫

题目链接:科大讯飞杯 迷宫


先跑出起点到每个点的最短路,然后每个点到终点的最短路。

然后枚举是否使用一次机会。

如果使用,枚举每个点,到能到的最小到终点的最短路,其实就是矩形查询min。直接ST表维即可。


AC代码:

#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include
//#define int long long
using namespace std;
const int N=2010,inf=0x3f3f3f3f;
const int dx[]={0,1,0,-1},dy[]={1,0,-1,0};
int vis[N][N][2],sx,sy,ex,ey,n,m,d,res=inf,a[10];	char g[N][N];
pair<int,int> pre[N][N][2];
vector<pair<int,int> > ans;
int st[N][N][14];
void init_st(){
    int i, j, k;
    for(k = 1; k <=12; ++k)
        for(i = 1; i <= n-(1<<k)+1; ++i)
        for(j = 1; j <= m-(1<<k)+1; ++j){
            int t1 = min(st[i][j][k-1], st[i+(1<<(k-1))][j][k-1]);
            int t2 = min(st[i][j+(1<<(k-1))][k-1], st[i+(1<<(k-1))][j+(1<<(k-1))][k-1]);
            st[i][j][k] = min(t1, t2);
        }
}
int ask(int x1, int y1, int x2, int y2){
    int k1 = log2(x2-x1+1);
    int k2 = log2(y2-y1+1);
    if(k1==k2) return min(st[x1][y1][k1],min(st[x2-(1<<k1)+1][y1][k1],
	min(st[x1][y2-(1<<k2)+1][k1], st[x2-(1<<k1)+1][y2-(1<<k2)+1][k1])));
    if(k1<k2){
        int k = k1;
        int minret = 0x3f3f3f3f;
        for(int i = y1; i <= y2 - (1<<k) + 1; i += (1<<k))
            minret = min(minret, min(st[x1][i][k], st[x2-(1<<k)+1][i][k]));
        minret = min(minret, min(st[x1][y2-(1<<k)+1][k], st[x2-(1<<k)+1][y2-(1<<k)+1][k]));
        return minret;
    }
    int k = k2;
    int minret = 0x3f3f3f3f;
    for(int i = x1; i <= x2-(1<<k)+1; i += (1<<k))
        minret = min(minret, min(st[i][y1][k], st[i][y2-(1<<k)+1][k]));
    minret = min(minret, min(st[x2-(1<<k)+1][y1][k], st[x2-(1<<k)+1][y2-(1<<k)+1][k]));
    return minret;
}
void bfs(int sx,int sy,int k){
	queue<pair<int,int> > q;	q.push({sx,sy});	vis[sx][sy][k]=0;
	while(q.size()){
		int x=q.front().first,y=q.front().second;	q.pop();
		for(int i=0;i<4;i++){
			int tx=x+dx[i],ty=y+dy[i];
			if(tx>=1&&tx<=n&&ty>=1&&ty<=m&&g[tx][ty]!='X'&&vis[tx][ty][k]==inf){
				vis[tx][ty][k]=vis[x][y][k]+1,q.push({tx,ty});
				pre[tx][ty][k]={x,y};
			}			
		}
	}
}
void dfs(int x,int y){
	if(!x||!y)	return ;
	if(pre[x][y][0].first)	dfs(pre[x][y][0].first,pre[x][y][0].second);
	ans.push_back({x,y});
}
void dfs1(int x,int y){
	if(!x||!y)	return ;
	ans.push_back({x,y});
	if(pre[x][y][1].first)	dfs1(pre[x][y][1].first,pre[x][y][1].second);
}
signed main(){
	cin>>n>>m>>d;	memset(vis,0x3f,sizeof vis);
	for(int i=1;i<=n;i++)	scanf("%s",g[i]+1);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(g[i][j]=='S')	sx=i,sy=j;
			if(g[i][j]=='T')	ex=i,ey=j;
		}
	}
	bfs(sx,sy,0),bfs(ex,ey,1);
	if(d==0){
		if(vis[ex][ey][0]==inf)	return puts("-1"),0;
		dfs(ex,ey);	cout<<vis[ex][ey][0]<<endl;
		for(auto s:ans)	printf("%d %d\n",s.first-1,s.second-1);
		return 0;
	}
	for(int i=1;i<=n;i++)	for(int j=1;j<=m;j++)	st[i][j][0]=vis[i][j][1];
	init_st();
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			int ak=vis[i][j][0]+1+ask(max(1,i-d),max(1,j-d),min(n,i+d),min(m,j+d));
			if(ak<res)	res=ak,a[1]=i,a[2]=j;
		}
	}
	if(res==inf)	return puts("-1"),0;
	dfs(a[1],a[2]);	int po=res-vis[a[1]][a[2]][0]-1;
	for(int i=max(1,a[1]-d);i<=min(n,a[1]+d);i++){
		for(int j=max(1,a[2]-d);j<=min(m,a[2]+d);j++){
			if(vis[i][j][1]==po){
				dfs1(i,j);
				cout<<res<<endl;
				for(auto s:ans)	printf("%d %d\n",s.first-1,s.second-1);
				return 0;
			}
		}
	}
	return 0;
}

你可能感兴趣的:(图论,bfs,ST表)