DFS专题
来源:互联网 发布:giftbox是什么软件 编辑:程序博客网 时间:2024/05/29 15:25
Description
玩家鼠标先后点击两块棋子,试图将他们消去,然后游戏的后台判断这两个方格能不能消去。现在你的任务就是写这个后台程序。
Input
注意:询问之间无先后关系,都是针对当前状态的!
Output
Sample Input
3 41 2 3 40 0 0 04 3 2 141 1 3 41 1 2 41 1 3 32 1 2 43 40 1 4 30 2 4 10 0 0 021 1 2 41 3 2 30 0
Sample Output
YESNONONONOYES
吐槽一下出题人文字表达能力,已在原文做修改。
代码:
#include<stdio.h>#include<string.h>#include<math.h>#include<stdlib.h>#include<vector>#include<queue>#include<stack>#include<iostream>#include<string>#include<algorithm>using namespace std;#define MaxSize 1005#define inf 0x3f3f3f3fint n,m,flag;int mp[MaxSize][MaxSize],book[MaxSize][MaxSize];int d[4][2]= {0,1,1,0,0,-1,-1,0};//右,下,左,上void dfs(int x, int y, int cnt, int dir,int tx, int ty){ if(x==tx&&y==ty) { flag=1; return; } if(x<0 || x>=n || y<0 ||y>=m||book[x][y]==1||mp[x][y]!=0) return;///////////////////开始剪枝/////////////// if(cnt>2) return; /*我最开始想的是,能走到这一步,说明前面说明没找到目标点, 如果此时的转弯次数大于等于2,再怎么走也不能在转弯2次内到目标点了。 才怪咧!这又不是step,如果当前已经转弯两次了,之后一直按这最后一次的方向走,走到目标点也是可以的呀*/ if(cnt==2)//如果已经转两次弯了,那么目标点必定只能在当前点方向的前方。 { if(dir == 0) { if(!(x == tx && ty > y)) return; } else if(dir == 2) { if(!(x == tx && ty < y)) return; } else if(dir == 1) { if(!(y == ty && tx > x)) return; } else if(dir == 3) { if(!(y == ty && tx < x)) return; } }///////////////////剪枝结束/////////////// book[x][y]=1; for(int i=0; i<4; i++) { if(dir==i) dfs(x+d[i][0],y+d[i][1],cnt,dir,tx,ty); else dfs(x+d[i][0],y+d[i][1],cnt+1,i,tx,ty); } book[x][y]=0;}int main(){ int x,y,tx,ty,q; while(~scanf("%d%d",&n,&m)) { if(n==0&&m==0) break; for(int i = 0; i < n; i++) { for(int j = 0; j < m; j++) { scanf("%d",&mp[i][j]); } } scanf("%d",&q); while(q--) { scanf("%d%d%d%d",&x,&y,&tx,&ty); x--,y--,tx--,ty--; if(mp[x][y]!=mp[tx][ty]||mp[x][y]==0||(x==tx&&y==ty)) printf("NO\n"); //注意如果是同一个点肯定是不能消去的【避坑之重复数据】 else { flag=0; memset(book,0,sizeof(book)); book[x][y]=1; for(int i=0; i<4; i++) { dfs(x+d[i][0],y+d[i][1],0,i,tx,ty); if(flag) break;//这里也能剪枝,剪的还是大枝。我真机智。 } if(flag) printf("YES\n"); else printf("NO\n"); } } } return 0;}//FROM CJZ
这道题其实不能从外面走还要简单一点,要是能从外面走的话,就在地图外面加一圈0即可。
思考:
1、在进入dfs判断的时候,我一开始是这样写的:
if(x<0 || x>=n || y<0 ||y>=m||book[x][y]==1||(mp[x][y]!=0&&(x!=tx&&y!=ty))) return; if(x==tx&&y==ty) { flag=1; return; }
因为我想的是我有可能此时走到了目标点,而这个点是非0的,所以这里要留出个条件给这种情况。然而这样的话,出现下面这中情况我的代码就不对了:
5 5
1 2 1 2 1
0 0 0 2 0
0 0 0 0 0
0 0 0 0 0
1 1 1 1 1
1
1 4 1 2
因为有可能路径中存在和查询点一样的点,把路径挡住。所以没有到达最后目标点之前,我们都不能允许路径中出现非0点。所以应该改成这样:
if(x==tx&&y==ty) { flag=1; return; } if(x<0 || x>=n || y<0 ||y>=m||book[x][y]==1||mp[x][y]!=0) return;
2、下面我们来说说这个结构:
void dfs(int x, int y, int cnt, int dir,int tx, int ty){ . . . . 判断&剪枝 . . . . book[x][y]=1; for(int i=0; i<4; i++) { if(dir==i) dfs(x+d[i][0],y+d[i][1],cnt,dir,tx,ty); else dfs(x+d[i][0],y+d[i][1],cnt+1,i,tx,ty); } book[x][y]=0;}
对于dfs而言,每一轮return之前,都出是走的一条路径。每一轮中,路径当中的所走过的每一个点都应该进行标记,来防止“贪吃蛇的自己咬到自己”的情况,即:走过的点不能重复走。
而对于这个结构而言,它先对当前点进行标记,然后对当前点进行扩展dfs。对于当前点,对由它为“起点”扩展出来的一堆堆点来说,这个当前点是被标记的,这很讲理嘛(自己想一想)。以这个点所有扩展出来的dfs都结束之后,再取消它的标记,结束以当前点为起始点的dfs路径。然后return到它的上一个点,上一个点又继续进行其他方向的dfs扩展。这种结构真是神奇,好好体会。
3、
void dfs(int x, int y, int cnt, int dir,int tx, int ty)
在bfs的时候,我们通常把点的其他属性(如:步数,时间)用结构体来存,这样在扩展的时候是没有什么问题的。而对于dfs,没有了bfs的队列节点储存结构,这些附加属性就可以写在函数的形参里面,这样扩展的时候这些属性就能照样进行步进了。
Description
For example ,consider the positive integer 145 = 1!+4!+5!, so it's a DFS number.
Now you should find out all the DFS numbers in the range of int( [1, 2147483647] ).
There is no input for this problem. Output all the DFS numbers in increasing order. The first 2 lines of the output are shown below.
Input
Output
Sample Output
12......
讲道理,这道题和dfs没一点关系。不过可以练习一下怎么打表。
打表代码:
#include<stdio.h>#include<string.h>#include<math.h>#include<stdlib.h>#include<vector>#include<queue>#include<stack>#include<iostream>#include<string>#include<algorithm>using namespace std;#define MaxSize 45#define inf 0x3f3f3f3fint jc[100];int main(){ jc[0]=1; int sum; int cnt ; int x ; sum=1; for(int i = 1; i <= 9; i++) { sum*=i; jc[i]=sum; } FILE *fp=fopen("dfs_num.txt","w+"); for(int i=1; i<=2147483647; i++) { sum=0; cnt = 0; x = i; while(x != 0) { sum+=jc[x%10]; x/=10; } if(sum==i) { fprintf(fp,"%d\\n",i); //fflush(fp); } } fclose(fp); return 0;}//FROM CJZ
最后出来4个数据1,2,145,40585,直接打表输出就可以了。
提交代码;
#include<stdio.h>int main(){ printf("1\n2\n145\n40585\n"); return 0;}
Description
Input
每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n
当为-1 -1时表示输入结束。
随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。
Output
Sample Input
2 1#..#4 4...#..#..#..#...-1 -1
Sample Output
21
#include<stdio.h>#include<string.h>#include<math.h>#include<stdlib.h>#include<vector>#include<queue>#include<stack>#include<iostream>#include<string>#include<algorithm>using namespace std;#define MaxSize 10#define inf 0x3f3f3f3f#define LL long long intint n,k,ans;int book[MaxSize];char mp[MaxSize][MaxSize];void dfs(int r, int cnt){ if(cnt == k) { ans++; return; } if(r == n) return;//上面这两个判断的顺序一定要这样写* for(int i=0; i<n; i++) { if( mp[r][i]=='.' || book[i]==1) continue; book[i]=1;//说明当前i可以选,则标记。然后cnt+1,继续找下一行 /**想一想如果是在最后一行(即n-1行)找到的最后一个cnt的情况, 这就决定了上面的return顺序。如果换一个顺序的话,这种情况下ans还没++就return了, 所以不行*/ dfs(r+1,cnt+1); book[i]=0; } /*并不是每一行都能找到满足条件的棋盘位置的, 如果就这样结束了的话,这次for没找到位置,没进行往后的dfs, 那么后面就断了。所以不难想到,没找到的话,我们应该有个跳行语句。 而且我们知道,在选位置的时候不一定必须一行一行挨着选, 我们可以跳过某行或者某几行(只要是满足条件的)。如果我们就只写个for就完了的话, 这明显就不能实现跳行了,所以我们让每个点多一个可以选择跳行的语句。 从以上两点来看,无论哪种情况,都应该在for结束之后有跳行的语句,即对于每一个点, 它要进行两种选择,一是在下一行里面选择合适的位置,二是跳过下一行,进入再下一行去选。 这里举个例子,比如我们要隔两行再开始选, 那么这里我们会经历dfs(r+1,cnt)进入下一行, 下一行的时候又会经历dfs((r+1)+1,cnt),所以一定会囊括所有跳行情况*/ dfs(r+1,cnt);}int main(){ while(~scanf("%d%d",&n,&k)) { if(n==-1 && k==-1) break; getchar(); for(int i=0; i<n; i++) { for(int j=0; j<n; j++) { scanf("%c",&mp[i][j]); } getchar(); } memset(book,0,sizeof(book)); ans=0; dfs(0,0); printf("%d\n",ans); } return 0;}//FROM CJZ
- DFS专题
- DFS专题
- ACdream dfs 专题
- bfs 和 dfs 专题
- dfs序专题学习
- DFS及其应用 专题
- bfs+dfs专题小结
- LeetCode专题----DFS
- acm.DFS深度搜索专题
- Binary Tree DFS遍历专题
- DFS专题--Hand in hand
- DFS&BFS专题(一)
- 专题 简单搜索(bfs+dfs) 个人题解
- BFS DFS 搜索专题合集
- 【算法专题】【搜索】【DFS】枚举全排列
- 搜索专题(DFS)HDU1181-变形课
- 搜索专题(DFS)HDU 1072-Nightmare
- dfs+bfs专题(简单题)
- input的onchange事件实际触发条件与解决方法
- 使用SQL Server 2008远程链接时SQL数据库不成功的解决方案
- 我的第一篇博客
- MyBatis在insert插入操作时返回主键ID的配置
- iOS之轮播图(collectionView)加定时器
- DFS专题
- 10036---深入浅出JMS(二)--ActiveMQ简单介绍以及安装
- js String对象(字符串操作)常用方法小结
- vi /vim使用方法
- 客户端每日一享
- 基于tcp的c/s模型的一个简单的socket实现
- Red packet【二分】
- nfs挂载一些指令
- 学习Maven----Intellij Idea创建Maven项目