Gym - 100971J ——DFS
Vitaly works at the warehouse. The warehouse can be represented as a grid of n × mcells, each of which either is free or is occupied by a container. From every free cell it's possible to reach every other free cell by moving only through the cells sharing a side. Besides that, there are two robots in the warehouse. The robots are located in different free cells.
Vitaly wants to swap the robots. Robots can move only through free cells sharing a side, moreover, they can't be in the same cell at the same time or move through each other. Find out if the swap can be done.
Input
The first line contains two positive integers n and m (2 ≤ n·m ≤ 200000) — the sizes of the warehouse.
Each of the next n lines contains m characters. The j-th character of the i-th line is «.» if the corresponding cell is free, «#» if there is a container on it, «1» if it's occupied by the first robot, and «2» if it's occupied by the second robot. The characters «1» and «2» appear exactly once in these lines.
Output
Output «YES» (without quotes) if the robots can be swapped, and «NO» (without quotes) if that can't be done.
Examples
5 3 ### #1# #.# #2# ###
NO
3 5 #...# #1.2# #####
YES 题意:给出了一个n*m (n*m<=200000)的字符矩阵,表示地图。矩阵中#表示被占用的地方,‘ . ’表示可以通过的地方,然后在矩阵中有两个数字1,2,分别表示两个机器人。机器人只能往上下左右走,且只能走向元素为‘ . ’的位置,两个机器人不能穿过对方,问你能不能交换两个机器人的位置(并不要求两个机器人同时走)。
思路:这题可以用DFS来写(这道题看了大佬的代码,绕的我头都晕了,对DFS的原理产生了怀疑!看了一天才看懂)
首先我们来分析一下什么情况下可以实现交换,首先两个机器人之间要有通路,但有通路还不够,要有两种情况才行。
第一种:1和2两个机器人之间有回路,就是他们两个在一个环上,那就可以在环上绕一圈,就完成了互换(如样例2)。
第二种:1和2之间有通路,且在机器人能够到达的所有点中,至少有一点的度大于2(度大于2就是说这个点的四个方向,至少三个不是障碍物),看下面的图来理解;

在上面的图中,A点的度就是3,因为他的上下和右都可以走;
如果要完成交换,1号可以先走到 B位置,然后让2号通过,1号再出来,去到2号原本的位置,便完成了交换。
但如果没有像A一样度为3的点,即使1和2有一条通路,也无法交换,因为1和2不能穿过对方。
如果1和2之间有多条通路且1,2不在回路上,那一定有度为3的点或环,因为要从一个点分出两条路来,分出的两条路是两个度,再加上走到这点的路,就是三个度。

就如上图,1到2有两条路,就一定存在一个如A一样的点,度为3,除非1,2在同一个环上(如样例2);
所以这题就和可以等同于求通路的条数,如果有两条通路(环也可以看成两条路)或一条通路但有一个点的度为3,那就YES,其余全是NO。
具体求法看代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
//#include<cmath>
#include<climits>
#include<algorithm>
#include<stack>
#include<queue>
#define eps 1e-7
#define ll long long
#define inf 0x3f3f3f3f
#define pi 3.141592653589793238462643383279
using namespace std;
int dir[][] = {,,-,,,,,-};
int dot[],vis[];
int x1,x2,y1,y2,ok,ans,flag; //x1,y1好像会和 cmath头文件里面的东西冲突,所以上面把这个头文件注释掉了
int n,m; int judge(int x,int y) //计算当前点的度数
{
int root = ;
if(x->= && dot[(x-)*m-m+y] )
root++;
if(x+<=n && dot[(x+)*m-m+y] )
root++;
if(y+<=m && dot[x*m-m+y+] )
root++;
if(y->= && dot[x*m-m+y-] )
root++;
return root;
} void DFS(int x,int y,int cnt)
{
//cout<<x<<' '<<y<<endl;
if( x == x2 && y == y2 ) ans++; //如果走到了终点,ans++;
//不用return,因为 可能在终点之后会有度大于2的点
if(!flag && x == x1 && y == y1 && cnt > )
//环找到一个就够了,防止出现1和2没有通路,但可以多次回到起点的情况,所以限制只走到起点一次
{
ans++;
flag = ;
} if( (!(ans== && flag) && (ans && ok) )|| ans> || vis[x*m-m+y] ) return;
//注意里面的判断条件,回溯的条件在这里面,而ans++的操作在上面,放在这里是为了防止你在将终点标记为走过后,就再也不能走到终点了
//ans要大于2而不是等于2,等于2不一定就是有两条路;
//因为照我这种写法,走到下一个点之后,从那个点遍历四个方向,还会回到终点,并在回溯前ans++,所以ans会重复计算一次;
//如果终点的度是2,并且只有一条路到终点,ans也会等于2,因为重复计算了一次,所以ans要大于2;
//终点的度为三时重复计算了两次,但不用在意,因为当有一个点的度为大于2时,有一条通路就够了,并不影响结果; vis[x*m-m+y] = ; if(!ok) //如果还没找到度大于2的点
{
if(judge(x,y) > ) //就判断当前点的度是否为 3
ok = ;
} for(int i=; i<; ++i)
{
int xx = x + dir[i][];
int yy = y + dir[i][];
if(xx>= && xx<=n && yy>= && yy<=m && dot[xx*m-m+yy])
{
DFS(xx,yy,cnt+);
}
}
return;
} int main()
{
char a;
cin>>n>>m;
ok = ans = flag = ;
memset(vis,,sizeof(vis)); //vis标记已走过的点,防止重复走
memset(dot,,sizeof(dot)); //dot标记可以为'.'的点
for(int i=; i<=n; ++i)
{
getchar();
for(int j=; j<=m; ++j)
{
scanf("%c",&a);
if(a != '#')
dot[i*m-m+j] = ;
if(a == '') //记录机器人1的位置
{
x1 = i;
y1 = j;
}
if(a == '') //记录机器人2的位置
{
x2 = i;
y2 = j;
}
}
} DFS(x1,y1,); //深搜 if(ans == && flag) //如果ans等于1,但flag=1,表示这个ans是走到起点才加上的,1和2之间并没有通路
cout<<"NO"<<endl;
else if( (ans && ok) || ans> )
cout<<"YES"<<endl;
else cout<<"NO"<<endl;
return ;
}
/*
5 3
###
#1#
#.#
#2#
###
3 5
#...#
#1.2#
#####
*/
上面的代码ans为什么要大于2比较难理解,可以试一下这一组样例,将搜索的每一步输出帮助理解:
3 3
1..
.#.
..2
输出的ans是3,且每一步走的是:
1 1
2 1
3 1
2 1
3 2
3 3 //ans++
2 3
3 3 //ans++
1 3
2 3
1 2
1 3
1 1
3 2
3 1
1 1 //ans++
1 2
可以看到,ans加了三次,而其中的第二次是重复计算,重复计算终点的次数等于终点的度-1;
首先只有能走到终点才会重复计算,当终点的度为2时重复计算了一次,所以ans==3才算有两条路,度为1时不会重复计算,度为3或4时无影响,因为有度为3的点时只要有通路就满足交换条件。
当然,还要防止起点被重复计算,所以标记只能走到起点一次。
还有,在代码中,即使这点标记为走过,还是要继续递归,因为不然终点被标记后就永远也走不到终点了。
Gym - 100971J ——DFS的更多相关文章
- 【Gym 100971J】Robots at Warehouse
题意 链接给你一个n*m的地图,'#'代表墙,‘.’代表可走的,1代表1号机器人,2代表2号机器人,机器人可以上下左右移动到非墙的位置,但不能走到另一个机器人身上.问能否交换1和2的位置. 分析 如果 ...
- Gym - 100971J (思维+简单bfs)
题目链接:http://codeforces.com/gym/100971/problem/J J. Robots at Warehouse time limit per test 2.0 s mem ...
- Gym 100989L (DFS)
AbdelKader enjoys math. He feels very frustrated whenever he sees an incorrect equation and so he tr ...
- Random Numbers Gym - 101466K dfs序+线段树
Tamref love random numbers, but he hates recurrent relations, Tamref thinks that mainstream random g ...
- ACM: Gym 100935G Board Game - DFS暴力搜索
Board Game Time Limit:2000MS Memory Limit:65536KB 64bit IO Format:%I64d & %I64u Gym 100 ...
- Gym 100463D Evil DFS
Evil Time Limit: 5 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100463/attachments Descri ...
- codeforces Gym 100187J J. Deck Shuffling dfs
J. Deck Shuffling Time Limit: 2 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100187/pro ...
- CodeForces Gym 100500A A. Poetry Challenge DFS
Problem A. Poetry Challenge Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/10 ...
- Codeforces Gym 100463D Evil DFS
Evil Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100463/attachments Descr ...
随机推荐
- Ubuntu Server如何配置SFTP(建立用户监狱)
Ubuntu Server如何配置SFTP(建立用户监狱) SSH File Transfer Protocol是一个比普通FTP更为安全的文件传输协议.(参考资料:http://en.wikip ...
- linux中awk工具
awk sed以行为单位处理文件,awk比sed强的地方在于不仅能以行为单位还能以列为单位处理文件.awk缺省的行分隔符是换行,缺省的列分隔符是连续的空格和Tab,但是行分隔符和列分隔符都可以自定义, ...
- 【源码阅读】Java集合之二 - LinkedList源码深度解读
Java 源码阅读的第一步是Collection框架源码,这也是面试基础中的基础: 针对Collection的源码阅读写一个系列的文章; 本文是第二篇LinkedList. ---@pdai JDK版 ...
- Unity Pitfall 汇总
[Unity Pitfall 汇总] 1. 当脚本被绑定到一个对象时,一个类对象即会被创建,此意味着此类构造函数会被调用.所以在构造函数中不要调用任何运行时才创建的类.相应的初始化方代码应该移至Sta ...
- Transform & Physics
[Transform & Physics] 1.Space.Unity定义了Space枚举值,此值如下: 通常通过Space.World.Space.Self来区别一个Vector是按世界坐标 ...
- SQL的3个主要组成
SQL语言包含3个部分:数据定义语言(DDL),数据操作语言(DML),数据控制语言(DCL) 数据定义语言(DDL) 数据定义语言用于定义和管理对象,例如数据库.数据表及视图等.典型代表有CREAT ...
- Android开发实战之ViewPager实现向导界面
当我们更新应用,或者第一次进入应用时都会有一个向导界面,介绍这个app的内容和使用方式. 如果你细心你会发现其实这就是个viewpager,本篇博文将介绍应用的向导界面是如何制作的.希 望本篇博文对你 ...
- 解决svn Key usage violation in certificate has been detected
ubuntu系统 #!/bin/shecho "This script will reconfigure subversion to work with certs correctly.&q ...
- Codeforces 1154F (DP)
题意:有一个人去买铲子,他需要买正好k把.每把铲子有个标价,并且每把铲子最多只能被买一次.有m种优惠方案,每个优惠方案xi, yi是指如果这次恰好购买了xi把铲子,那么这次购买的铲子中最便宜的yi把将 ...
- [Fiddler]如何让Fiddler可以抓取https的请求
Fiddler通过在本机开启了一个http的代理服务器来进行http请求和响应转发,默认情况下,并不能抓取https的请求.下面小编就来介绍下,如何用fiddler来抓取https的请求. 1.打开F ...