1.传送门

Posted ghouls

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了1.传送门相关的知识,希望对你有一定的参考价值。

题三:传送门

 

【问题描述】

用一个n*n的矩阵表示一个岛屿,岛屿中有陆地和水域,陆地用0表示,水域用1表示,你只能在陆地上行走,在陆地上行走不需要花费任何费用,给定起点的坐标(sx,sy)与终点坐标(ex,ey),保证这两个点必定是陆地。 
你可以在任意两块陆地上建立一个传送门且最多只能建一个传送门,传送门可以使两个点互达,费用是两点间横坐标、纵坐标的差的平方和,即(sx-ex)^2+(sy-ey)^2。 
求从起点起到终点的最小花费,若不需要建传送门可直接到达终点则花费为0。

 

【输入格式】

为了有效防止骗分有多组测试数据。 
第一行输入一个正整数t(2≤t≤10),表示测试数据的组数。 
对于第组测试数据输入如下: 
第一行输入一个正整数n(1≤n≤100)。 
第二行输入起点坐标sx,sy。 
第三行输入终点坐标ex,ey。 
接下来的n行输入一个n*n的01矩阵,0与1之间无空格,详见样例。

 

【输出格式】

对于每组测试数据输出一行,即一个整数表示该组数据的最小花费。

 

【样例输入】



1 1 
5 5 
00001 
11111 
00111 
00110 
00110 

1 3 
3 1 
010 
101 
010 

1 1 
2 2 
00 
10

 

【样例输出】

10 

0

 

【数据规模】

对于100%的数据,2≤t≤10,1≤n≤100。

 

【算法分析】

这道题的地图,关于起点与终点的位置关系,无非就两种情况, 
1.起点与终点被贯穿整张地图的水域分开(即河),这时它们位于两块不同的”大陆“上,如图

技术图片

2.起点和终点在同一块大陆上,如图

技术图片
所以我们可以以起点和终点为开始的点分别做一遍搜索,把起点和终点所能到达的点分别打上标记,这时又会出现两种情况, 
1.在给终点打标记的时候,打到了起点能到的点(即已经被打过标记的点),这种情况说明起点和终点在同一块”大陆“上,输出”0“即可 
2.在给终点打标记的过程中始终未打到起点能到的点,这种情况说明起点和终点在两块不同的“大陆”上,那么我们就需要枚举在每个起点能到的点和每个终点能到的点之间打开传送门的价格,取其最小值即可。

 

【AC代码】

 
#include<bits/stdc++.h>
#define For(i,j,n) for(int (i)=(j);(i)<=(n);(i)++)
using namespace std;
int n,sx,sy,ex,ey;
char a[110][110];
int flag[110][110],river[110][110];
bool tt=false;
void work1(int x,int y) 
    flag[x][y]=1;
    if((a[x+1][y]==‘1‘||flag[x+1][y]==1)&&(a[x][y+1]==‘1‘||flag[x][y+1]==1)&&(a[x-1][y]==‘1‘||flag[x-1][y]==1)&&(a[x][y-1]==‘1‘||flag[x][y-1]==1)) return;
    if(a[x+1][y]==‘0‘&&!flag[x+1][y]) 
        flag[x+1][y]=1;
        work1(x+1,y);
    
    if(a[x][y+1]==‘0‘&&!flag[x][y+1]) 
        flag[x][y+1]=1;
        work1(x,y+1);
    
    if(a[x-1][y]==‘0‘&&!flag[x-1][y]) 
        flag[x-1][y]=1;
        work1(x-1,y);
    
    if(a[x][y-1]==‘0‘&&!flag[x][y-1]) 
        flag[x][y-1]=1;
        work1(x,y-1);
    

void work2(int x,int y) 
    if(flag[x][y]==1) 
        cout<<0<<endl;
        tt=true;
        return ;
    
    flag[x][y]=2;
    if((a[x+1][y]==‘1‘||flag[x+1][y]==2)&&(a[x][y+1]==‘1‘||flag[x][y+1]==2)&&(a[x-1][y]==‘1‘||flag[x-1][y]==2)&&(a[x][y-1]==‘1‘||flag[x][y-1]==2)) return;
    if(a[x+1][y]==‘0‘&&flag[x+1][y]!=2) 
        flag[x+1][y]=2;
        work2(x+1,y);
    
    if(a[x][y+1]==‘0‘&&flag[x][y+1]!=2) 
        flag[x][y+1]=2;
        work2(x,y+1);
    
    if(a[x-1][y]==‘0‘&&flag[x-1][y]!=2) 
        flag[x-1][y]=2;
        work2(x-1,y);
    
    if(a[x][y-1]==‘0‘&&flag[x][y-1]!=2) 
        flag[x][y-1]=2;
        work2(x,y-1);
    

int ans;
int main() 
    ios::sync_with_stdio(false);
    int q;
    cin>>q;
    while(q--) 
        tt=false;
        cin>>n;
        cin>>sx>>sy>>ex>>ey;
        For(i,1,n) 
            for(int j=1; j<=n; j++) 
                cin>>a[i][j];
                flag[i][j]=0;
            
        
        For(i,0,n+1) 
            a[i][0]=a[i][n+1]=a[0][i]=a[n+1][i]=1;
            flag[i][0]=flag[i][n+1]=flag[0][i]=flag[n+1][i]=0;
        
        For(i,0,n+1) For(j,0,n+1) flag[i][j]=0;
        work1(sx,sy);
        work2(ex,ey);
        if(tt) continue;
        ans=0x7ffffff;
        For(i,1,n) For(j,1,n) For(i1,1,n) For(j1,1,n) if(flag[i][j]==1&&flag[i1][j1]==2)ans=min(ans,(i-i1)*(i-i1)+(j-j1)*(j-j1));
        cout<<ans<<endl;
    

  

以上是关于1.传送门的主要内容,如果未能解决你的问题,请参考以下文章

[Unity]简易传送门效果

2022-01-06:N个结点之间,表世界存在双向通行的道路,里世界存在双向通行的传送门. 若走表世界的道路,花费一分钟. 若走里世界的传送门,不花费时间,但是接下来一分钟不能走传送门. 输入: T为

学生会管理系统-后端个人总结

[题解]北京2018

我的数论练习

我的数论练习