图论第二章图的遍历与活动网络问题
来源:互联网 发布:淘宝网壹号人家 编辑:程序博客网 时间:2024/06/07 07:41
图的遍历 搜索
2.1 DFS遍历
ZOJ 2110 骨头的诱惑
类似于走迷宫问题 从狗的位置在限定步骤内走到骨头的位置 其中有'X'作为墙壁 不能走
dfs()之前要将当前位置设为'X' 之后要恢复现场 设为'.'
程序中有用到剪枝的思想!!!
代码如下:
#include <iostream>#include <cstdio>#include <cmath>using namespace std;char map[9][9];int di,dj;int n,m,t;bool escape;int dir[4][2]={{0,-1},{0,1},{1,0},{-1,0}};void dfs(int si,int sj,int cnt){ int i,temp; if(si>n||sj>m||si<=0||sj<=0) return; if(si==di&&sj==dj&&t==cnt) { escape=1; return; } temp=(t-cnt)-fabs(si-di)-fabs(sj-dj); if(temp<0||temp%2) return; for(i=0;i<4;i++) { if(map[si+dir[i][0]][sj+dir[i][1]]!='X') { map[si+dir[i][0]][sj+dir[i][1]]='X'; dfs(si+dir[i][0],sj+dir[i][1],cnt+1); if(escape) return; map[si+dir[i][0]][sj+dir[i][1]]='.'; } } return;}int main(){ int si,sj; while(scanf("%d%d%d",&n,&m,&t)!=EOF) { if(n==0&&m==0&&t==0) break; int wall=0; char temp; scanf("%c",&temp); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { scanf("%c",&map[i][j]); if(map[i][j]=='S') {si=i;sj=j;} else if(map[i][j]=='D') {di=i;dj=j;} else if(map[i][j]=='X') wall++; } scanf("%c",&temp); } if(n*m-wall<=t) { puts("NO"); continue; } escape=0; map[si][sj]='X'; dfs(si,sj,0); if(escape) puts("YES"); else puts("NO"); } return 0;}//AC一个有问题的代码 运行事例答案不对,贴出来 里面有注释:#include <iostream>#include <cstdio>#include <cmath>using namespace std;char map[9][9];int n,m,t;int di,dj; //门的位置bool escape; //是否成功逃脱int dir[4][2]={{0,-1},{0,1},{1,0},{-1,0}};//分别表示下,上,左,右void dfs(int si,int sj,int cnt){ int i,temp; if(si>n||sj<m||si<=0||sj<=0) return; if(si==di&&sj==dj&&cnt==t) { escape=1; return; }//abs(x-ex)+abs(y-ey)表示现在所在格子到目标格子的距离//t-cnt是实际还需要的步数//如果temp<0或者temp为奇数 那就不可能到达 temp=(t-cnt)-fabs(si-di)-fabs(sj-dj);//搜索过程中的剪枝 if(temp<0||temp%2) return; for(i=0;i<4;i++) { if(map[si+dir[i][0]][sj+dir[i][1]]!='X') { //前进方向 将当前方格设置为墙壁'X' map[si+dir[i][0]][sj+dir[i][1]]='X'; dfs(si+dir[i][0],sj+dir[i][1],cnt+1); if(escape) return; map[si+dir[i][0]][sj+dir[i][1]]='.';//后退方向 恢复现场 } } return;}int main(){ int si,sj; while(scanf("%d%d%d",&n,&m,&t)!=EOF) { if(n==0&&m==0&&t==0) break; int wall=0; char temp; scanf("%c",&temp); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { scanf("%c",&map[i][j]); if(map[i][j]=='S') {si=i;sj=j;} else if(map[i][j]=='D') {di=i;dj=j;} else if(map[i][j]=='X') wall++; } scanf("%c",&temp); } if(n*m-wall<=t) { puts("NO"); //cout<<1<<endl; continue; } escape=0; map[si][sj]='X'; dfs(si,sj,0);// cout<<escape<<endl; if(escape) puts("YES"); else puts("NO"); } return 0;}
POJ 1562 油田 Oil Deposits
'@'表示一块油田 '*'表示没有油田 油田连在一起的视为一块油田 相连的方式有对角线 水平 垂直
所以对一个点搜索有八个方向 这个与上题的区别就是遍历'@'点之后把这点设为'*'且遍历完之后不要恢复现场
做这种题目遍历的时候要注意边界的判断
代码如下:
#include <iostream>#include <cstdio>using namespace std;char grid[101][101];int m,n;int dir[8][2]={{-1,-1},{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1}};//八个方向void dfs(int x,int y){ int xx,yy; grid[x][y]='*'; for(int i=0;i<8;i++) { xx=x+dir[i][0]; yy=y+dir[i][1]; if(xx<0||y<0||xx>=m||y>=n) continue; if(grid[xx][yy]=='@') dfs(xx,yy); }}int main(){ while(scanf("%d%d",&m,&n)!=EOF) { //getchar(); if(m==0) break; for(int i=0;i<m;i++) scanf("%s",grid[i]); int count=0; for(int i=0;i<m;i++) { for(int j=0;j<n;j++) { if(grid[i][j]=='@') { dfs(i,j); count++; } } } printf("%d\n",count); } return 0;}
ZOJ2412 农田灌溉
管道问题 其实这题跟上题类似 就是看有多少块是相连的 只要管道口是相连的就可以
首先要将管道口的方向合理转化 顺时针方向 上右下左依次 定义一个数组 1表示该方向有管道 0表示没有
还要注意深搜的条件判断 给一个vis 数组 用来判断这个点有木有被访问过
代码如下:
#include <iostream>#include <cstdio>#include <cstring>using namespace std;int m,n;int map[55][55];bool vis[55][55];int dir[11][4]={{1,0,0,1},{1,1,0,0},{0,0,1,1},{0,1,1,0},{1,0,1,0},{0,1,0,1},{1,1,0,1},{1,0,1,1},{0,1,1,1},{1,1,1,0},{1,1,1,1}};void dfs(int x,int y){ vis[x][y]=1; for(int z=0;z<4;z++) { if(z==0&&dir[map[x][y]][z]&&x>=1&&dir[map[x-1][y]][2]&&!vis[x-1][y]) dfs(x-1,y); else if(z==1&&dir[map[x][y]][z]&&y<=n-2&&dir[map[x][y+1]][3]&&!vis[x][y+1]) dfs(x,y+1); else if(z==2&&dir[map[x][y]][z]&&x+1<m&&dir[map[x+1][y]][0]&&!vis[x+1][y]) dfs(x+1,y); else if(z==3&&dir[map[x][y]][z]&&y-1>=0&&dir[map[x][y-1]][1]&&!vis[x][y-1]) dfs(x,y-1); }}int main(){ while(scanf("%d%d",&m,&n)!=EOF) { if(m<0||n<0) break; memset(map,0,sizeof(map)); char ch[55]; for(int i=0;i<m;i++) { scanf("%s",ch); for(int j=0;j<n;j++) { map[i][j]=ch[j]-'A'; } } memset(vis,0,sizeof(vis)); int count=0; for(int i=0;i<m;i++) { for(int j=0;j<n;j++) { if(vis[i][j]) continue; dfs(i,j); count++; } } printf("%d\n",count); } return 0;}
zoj 1008 Gnoma Tetravex
题目大意 就是移动正方形 使得左右相邻的数字相等 上下相邻的数字相等
注意这里面可能会有一模一样的正方形
照着别人的思路写的代码 老是WA 不知道什么情况 贴个代码:
#include <iostream>#include <cstdio>#include <cstring>using namespace std;struct node{ int top,rig,bot,lef; int num;};node no[25],map[5][5];int n,kinds;bool suc;void dfs(int x){ if(x==n*n) { suc=1; return; } if(suc) return; for(int i=0;i<kinds;i++) { if(no[i].num&&(x%n==0||no[i].lef==map[x/n][x%n-1].rig)&&(x/n==0||no[i].top==map[x/n-1][x%n].bot)) { map[x/n][x%n]=no[i]; no[i].num--; dfs(x+1); no[i].num++; } }}int main(){ node temp; int count=0; while(scanf("%d",&n)!=EOF) { if(n==0) break; kinds=0; for(int i=0;i<n*n;i++) { scanf("%d%d%d%d",&temp.top,&temp.rig,&temp.bot,&temp.lef); temp.num=1; bool flag=1; for(int j=0;j<kinds;j++) { if(temp.top==no[j].top&&temp.rig==no[j].rig&&temp.bot==no[j].bot&&temp.lef==no[j].lef) { flag=0; no[j].num++; break; } } if(flag) { no[kinds++]=temp; } } suc=0; dfs(0); if(count) puts(""); if(suc) printf("Game %d:Possible\n",++count); else printf("Game %d:Impossible\n",++count); } return 0;}
ZOJ 2165 Red And Black
题目大意:类似于迷宫问题 就是‘.’表示黑色砖块 可以走的 '#'表示红色砖块 不可以走的
'@'为人初始的位置 计算能走的砖块的个数
代码如下:比较简单
#include <iostream>#include <cstdio>#include <cstring>using namespace std;char map[20][20];int si,sj;bool vis[20][20];int dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}};int count;int w,h;void dfs(int x,int y){ count++; map[x][y]='#'; for(int i=0;i<4;i++) { int m=dir[i][0]+x,n=y+dir[i][1]; if(m<0||n<0||m>=h||n>=w) continue; else { if(map[m][n]=='.') { dfs(m,n);// map[m+x][n+y]='.'; } } }}int main(){ while(scanf("%d%d",&w,&h)!=EOF) { getchar(); count=0;// memset(vis,0,sizeof(vis)); if(w==0&h==0) break; char temp; for(int i=0;i<h;i++) { for(int j=0;j<w;j++) { scanf("%c",&map[i][j]); if(map[i][j]=='@') { si=i; sj=j; } } scanf("%c",&temp); } map[si][sj]='#';//要防止那个人往回走 所以要把 走过的点设为'#' dfs(si,sj); printf("%d\n",count); } return 0;}
BFS
ZOJ 1649 Rescue
题目大意就是一个人被困监狱中,他的朋友去救他,其中有点表示墙壁,警卫,走一格用一个时间单位,遇到警卫将其打死另外加一个时间单位,墙壁不能走过去,求所需的最少时间。
这题中求最小步骤的若干方案中的最小时间不一定是最优解一定要等到队列为空,BFS过程结束后才能求得最优解
代码如下:
#include <cstdio>#include <cstring>#include <queue>#define MAXMN 210#define INF 1000000 //走到每个位置所需时间的初始值为无穷大using namespace std;struct point{ int x,y; int step;//走到当前位置所需的步数 int time;//走到当前位置所需的时间};queue<point> Q;int N,M; //监狱的大小char map[MAXMN][MAXMN];int mintime[MAXMN][MAXMN];int dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}};int ax,ay;//Angel所处的位置int BFS(point s){ int i; Q.push(s); point hd;//从队列头出列的位置 while(!Q.empty()) { hd=Q.front(); Q.pop(); for(i=0;i<4;i++) { //判断能否移动到相邻位置(x,y) int x=hd.x+dir[i][0],y=hd.y+dir[i][1]; if(x>=0&&x<=N-1&&y>=0&&y<=M-1&&map[x][y]!='#')//排除边界和墙壁 { point t; t.x=x;t.y=y; t.step=hd.step+1; t.time=hd.time+1; if(map[x][y]=='x') t.time++; //如果这种走法比之前走到(x,y)位置所花时间少 则把t入队列 if(t.time<mintime[x][y]) { mintime[x][y]=t.time; Q.push(t); } } } } return mintime[ax][ay];}int main(){ while(scanf("%d%d",&N,&M)!=EOF) { memset(map,0,sizeof(map)); for(int i=0;i<N;i++) scanf("%s",map[i]); int sx,sy; point start;//朋友的位置 for(int i=0;i<N;i++) for(int j=0;j<M;j++) { mintime[i][j]=INF; if(map[i][j]=='a') {ax=i;ay=j;} else if(map[i][j]=='r') {sx=i;sy=j;} } start.x=sx; start.y=sy; start.step=0; start.time=0; mintime[sx][sy]=0; int mint=BFS(start);//返回到达Angel位置最少时间 有可能为INF if(mint<INF) printf("%d\n",mint); else printf("Poor ANGEL has to stay in the prison all his life.\n"); } return 0;}
//待续 欢迎大家评论给点建议
- 图论第二章图的遍历与活动网络问题
- 第二章 活动图
- 网络文化节第二周的活动安排
- Android:第二章活动的基本用法
- 状态图与活动图
- 活动图与流程图的区别
- 状态图与活动图的比较
- 活动图与流程图的区别
- 活动图与流程图的区别
- uml活动图的概念与作用
- uml活动图的概念与作用
- 活动图与流程图的主要区别
- UML,活动图与状态图
- 第二章 先从看到的入手探究活动
- 第二章 先从看得到的入手-探究活动
- 第一行代码学习笔记-第二章 探究活动-1.活动的基本用法
- 第一行代码学习笔记-第二章 探究活动-3.活动的生命周期
- 第一行代码学习笔记-第二章 探究活动-4.活动的启动模式
- Android.mk各种文件编译汇总
- x264的nal分析
- 可恨的BOM?!
- Java内省机制
- 为何越容易得到越不知珍惜?
- 图论第二章图的遍历与活动网络问题
- 安卓拍照程序4.4可用
- Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC
- 【算法题集锦之三】--迷宫的随机生成和路径搜索
- linux 下的rar解压命令
- poj 3321 树状数组
- 7.17_java学习_静态代码块
- 程序员生存定律——成长路上常见的坑
- flex java传进制文件小结