1 条题解

  • 0
    @ 2025-8-24 22:23:32

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Zimo_666
    年少得志未必是什么好事.

    搬运于2025-08-24 22:23:32,当前版本为作者最后更新于2023-07-11 20:38:07,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    P6742 [BalticOI 2014 Day2] Portals

    Description

    给定一个 R×CR\times C 的迷宫,每个格子都有一种方块:

    • # 墙,不可以走,不可以穿过
    • . 路,可以走
    • S 出生点,玩家从这里开始走,只有一个
    • C 终点,玩家要到达这里,只有一个

    现在要对迷宫进行扩容,周围要增加一个方块 #,变成 (R+2)×(C+2)(R+2)\times (C+2) 的迷宫。

    并且在任何时候,它都可以向上、左、下、右四个方向中的一个发射传送门。当一个传送门被发射,它会一直向发射的方向飞行,直到碰触到墙壁。这时,传送门会被放置在这堵墙上。

    走一格需要 11 的时间,穿梭传送门也需要 11 的时间。

    求从出生点到终点最少需要多少时间。

    Solution

    我们简单造几组数据后发现有一种最优策略为两个传送门在同一点释放。于是我们考虑建边策略,我们首先可以把点 uu 上下左右相邻的并且在图内的点连边。

    而后我们考虑传送门的连边方法,我们先预处理出向各个方向可以到的墙的距离,而后我们比较这四种方案,得出一种走到传送门前等待传送的最小 disdis 并把这个点连接这四个墙点,边权均为 dis+1dis+1。注意若 uu 与某墙点长度恰好是 disdis 也就意味着直接走不需要传送就可以花费 disdis 到达,因而这条最小边(可能不唯一)边权应为 disdis 而非 dis+1dis+1。这样我们就完成了建边,直接在图上跑最短路即可。

    Code

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=1e3+7;
    int n,r,c;
    char mp[N][N];
    int s,t;
    int lf[N][N],rg[N][N],up[N][N],dn[N][N];
    vector<pair<int,int>> G[N*N];
    int dis[N*N];
    bool _vis[N*N];
    
    struct node{
    	int dis,id;
    	friend bool operator < (node a,node b){
    		return a.dis>b.dis;
    	}
    };
    
    void Dj(int s){
    	memset(_vis,0,sizeof _vis);
    	priority_queue<node> q;
    	memset(dis,80,sizeof dis);
    	dis[s]=0;
    	q.push({0,s});
    	while(!q.empty()){
    		int u=q.top().id;
    		q.pop();
    		if(_vis[u]) continue;
    		_vis[u]=1;
    		for(auto i:G[u]){
    			int k=i.first,w=i.second;
    			if(dis[k]>dis[u]+w){
    				dis[k]=dis[u]+w;
    				q.push({dis[k],k});
    			}
    		}
    	}
    }
    
    bool query(int x,int y){
    	return (mp[x][y]=='.'||mp[x][y]=='S'||mp[x][y]=='C');
    }
    
    int get(int x,int y){
    	return x*c+y-c;
    }
    
    void add(int u,int v,int w){
    	G[u].push_back(make_pair(v,w));
    }
    
    void read(){
    	scanf("%d%d",&r,&c);
    	n=r*c;
    	for(int i=1;i<=r;i++){
    		for(int j=1;j<=c;j++){
    			cin>>mp[i][j];
    			if(mp[i][j]=='S') s=get(i,j);
    			if(mp[i][j]=='C') t=get(i,j);
    		}
    	}
    }
    
    void deal(){
    	for(int i=1;i<=r;i++){
    		for(int j=1;j<=c;j++){
    			if(mp[i][j]=='#') lf[i][j]=j;
    			else lf[i][j]=lf[i][j-1];
    		}
    	}
    	for(int j=1;j<=c;j++){
    		for(int i=1;i<=r;i++){
    			if(mp[i][j]=='#') up[i][j]=i;
    			else up[i][j]=up[i-1][j];
    		}
    	}
    	for(int i=1;i<=r;i++){
    		rg[i][c+1]=c+1;
    		for(int j=c;j;j--){
    			if(mp[i][j]=='#') rg[i][j]=j;
    			else rg[i][j]=rg[i][j+1];
    		}
    	}
    	for(int j=1;j<=c;j++){
    		dn[r+1][j]=r+1;
    		for(int i=r;i;i--){
    			if(mp[i][j]=='#') dn[i][j]=i;
    			else dn[i][j]=dn[i+1][j];
    		}
    	}
    }
    
    void work(){
    	for(int i=1;i<=r;i++){
    		for(int j=1;j<=c;j++){
    			if(query(i,j)){
    				int L=lf[i][j]+1,R=rg[i][j]-1,U=up[i][j]+1,D=dn[i][j]-1;
    				int _dis=min({j-L+1,R-j+1,i-U+1,D-i+1});
    				int _L=get(i,L),_R=get(i,R),_U=get(U,j),_D=get(D,j);
    				int _pos=get(i,j);
    				add(_pos,_L,min(_dis,j-L)),add(_pos,_R,min(_dis,R-j)),add(_pos,_U,min(_dis,i-U)),add(_pos,_D,min(_dis,D-i));
    				if(query(i,j+1)) add(_pos,get(i,j+1),1); 
    				if(query(i+1,j)) add(_pos,get(i+1,j),1); 
    				if(query(i-1,j)) add(_pos,get(i-1,j),1); 
    				if(query(i,j-1)) add(_pos,get(i,j-1),1);
    			}
    		}
    	}
    	Dj(s);
    	printf("%d\n",dis[t]);
    //	for(int i=1;i<=n;i++) printf("%d ",dis[i]);
    }
    
    int main(){
    	read();
    	deal();
    	work();
    	return 0;
    }
    
    • 1

    信息

    ID
    5774
    时间
    1000ms
    内存
    256MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者