DFS&BFS专题(一)
2017-07-30 23:13
369 查看
题目列表
1.POJ-1321(简单DFS)
2.POJ-2251(三维坐标BFS)
3.POJ-1426(DFSf构造)
4.POJ-3087(BFS模拟)
5.POJ-3414(BFS模拟+记录路径)
6.UVA-11624(两次BFS)
7.POJ-3984(简单DFS&BFS都可以,记录路径)
8.HDU-1241(DFS种子填充)
9.HDU-1495(BFS求最短路)
10.HDU - 2612 (两次BFS)
Q1:POJ - 1321
题意:中文题
思路:
DFS的参数是从第i行往下搜索,设置num表示目前已经放好的棋子,如果num==k,放置的种数加1,如果递归层数大于n直接返回结束递归
Q2:POJ-2251
题意:
在一个立体空间, 输入三个数,L,R,C,代表有L个平面,R行,C列,.代表可以走,#代表不能走,S代表开始点,E代表结束点,问从S开始走,对每个位置,有六个走法,即空间的六个方向的走法(上下东南西北),一分钟可以走一个点,问从S走到E点,最少可以经过多少分钟,若不能到达,则输出Trapped!
思路:
简单BFS运用,只是把普通的二维平面变成了三维立体,由四个方向变成了六个方向
Q3:POJ-1426
题意:
给你一个[1,200]之间的整数n,要你求它的一个非0倍数m,这个m的十进制数只包含0和1.m不超过100位.
思路:
由于本题的数只有0和1构成,自然就想到了自己构造这个符合要求的数。所以这里我用DFS来构造这个数。虽然本题说最终结果数<=100位,但是经过测试本题测试数据中需要构造的数在unsigned long long 范围内有解,所以下面我用unsigned long long来表示需要构造的数。(并没有用高精度大整数)
DFS构造过程很简单了,就是每层循环向个位添加一个0或1即可。但是记得如果找到了一个合法的数要及时退出所有DFS递归函数。
Q4:POJ-3087
题意:
给定长度都为C两个字符串,S1,S2,和一个要求的结果字符串S12。先把 S2 的最下面一张牌放在最下面,然后S1,S2交错的叠放,得到新的S12,再把S12最下面的C个字符赋值给S1,把剩下的赋值给S2,再次重复上面的过程。最后求出要得到目标字符串S,问最少需要几步。
思路:
直接BFS模拟,将下一步可得的结果放入队列中(题目所给出的输入是从低向上排列的。)
Q5:POJ-3414
题意:
给你两个容器 A B 问是否能够经过有限的步骤倒水,得到容量为 C 的水
输出最小的步数,同时输出每一步的操作。
如果不能达到目标状态,则输出 impossible
思路:
总状态只有那么多, 反正每一步后都只有 6 种操作明显的 BFS 关键是每一步路径的记录。
开始用 BFS + 容器做了一遍,发现还是无法处理好输出路径问题,只好重新开始用数组模拟。
容器虽然很好用又方便,但是在不考虑内存的状况下,效率终究比不上数组模拟的了。
注意到 A 和 B 的范围是 1 到 100 的整数,
那么我们可以用vis[i][j]来记录每一种状态 0 <= i, j <= 100 ;
i 表示目前 A 容器中的水, j 表示目前 B 容器中的水
应该很容易就能分析出,对应于每一种状态的下一步只有六种情况:
一:用水池中的水装满 A
二:用水池中的水装满 B
三:把 A 中的水全部倒进废水池
四:把 B 中的水全部倒进废水池
五:把 A 中的水倒进 B 【不能溢出】
那么对应可能会有两种状态:用 k1 表示 A 中的水, k2 表示 B 中的水
如果 k1+k2 <= B 则 k2 = k1+k2; k1 = 0 【不能够装满容器 B】注意顺序
否则 k1 = k1+k2-B; k2 = B 【能够装满容器 B】
六:把 B 中的水倒进 A 【不能溢出】
也有两种情况,分析同上
如果 k1+k2 <= A 则 k1 = k1+k2; k2 = 0;
否则 k2 = k1+k2-A; k1 = A
用结构体数组来模拟队列
用 k1,k2 来记录当前容器中水的状态
前面已经分析过对应于每种情况只有 6 种操作, 那么对应每种情况的操作记录为 1 到 6 输出时处理下就好了。
当然少不了记录到当前状态最少用了多少步数 step
因为要记录路径,所以定义一个 f 来记录上一步在数组模拟队列中的下标。
最后如果能够达到目的,在判定最后一步的时候记录下最后一步在数组中的编号 lastIndex
然后从lastIndex从后往前找【f】前一个步骤在数组中的编号存在 id[] 中
最后再按照扫描出的路径依次遍历即可。
Q6:UVA-11624
题意:
在一个矩形方阵里面,一个人要从一个位置走向另一个位置,其中某些地方有火源,每过一分钟,火源就会点燃相邻的点,同时相邻的点也变成了火源。人不能通过有火的点。问一个人能够安全地走到目的地去?最短时间多少?
思路:
Joe的起点唯一,但是起火的地方并不是唯一的,这是我们首先要明确的。
关键是之后应该怎样处理火势的蔓延与Joe逃跑这两个过程的关系,我们要清楚:只有火势可以影响Joe的逃跑路线,但Joe的逃跑路线绝对不能影响火势,所以这两个过程不可能出现在同一个BFS中。
可以这样想:既然火势的蔓延时不随人的主观意愿而改变的,那么我们可以先让火势肆意蔓延,看它到底能烧到哪里,以及烧到某个地方所需要的时间,这样,主人公在逃跑的过程中,只要在火势到达之前赶到某个地方就可以了。
综上,需要两个BFS,第一个计算火势蔓延到任意一点所需要的时间,如果火势永远到达不了某些点,就把这些点的时间设为正无穷,之后再搜索Joe的逃跑路线,条件要增加时间这一项,只要Joe能到达迷宫的边界,就算逃出来了。
Q7:POJ-3984
题意:
中文题
思路:
反正就是简单的结构体套结构体存一下父节点就行,由于记录路径,这里直接用数组代替队列
Q8:HDU-1241
题意:
就是给你一个地图,找出所有不相连(八个方向)的@组合有多少个
思路:
先对整个地图进行遍历,找到一个入口,然后用DFS深搜,相连的@都找到,并且将其标记为1,再找下一个入口,再DFS能够到达的所有@标记为2,最后的数字就是油田的数量。
Q9:HDU - 1495
题意:
中文题
思路:
我们有明确的初始状态(s=s,a=0,b=0)和终止状态(s=s>>1,a=s>>1,b=0) (PS:a为大号杯)
而每一步我们都有六个可选择的方向(s->a ;s->b ; a->s ; a->b ;b->s ;b->a),我们要得到最少的倒的次数,当然就是bfs咯。
Q10:HDU - 2612
题意:
Y和M要在KFC约会,地图上有多个KFC,求在哪个KFC两人所走总距离最短,(注意KFC可以当做路)
思路:
用2次BFS,分别求出2个点到各个KFC的最短距离,然后找出和最小的即可
1.POJ-1321(简单DFS)
2.POJ-2251(三维坐标BFS)
3.POJ-1426(DFSf构造)
4.POJ-3087(BFS模拟)
5.POJ-3414(BFS模拟+记录路径)
6.UVA-11624(两次BFS)
7.POJ-3984(简单DFS&BFS都可以,记录路径)
8.HDU-1241(DFS种子填充)
9.HDU-1495(BFS求最短路)
10.HDU - 2612 (两次BFS)
Q1:POJ - 1321
题意:中文题
思路:
DFS的参数是从第i行往下搜索,设置num表示目前已经放好的棋子,如果num==k,放置的种数加1,如果递归层数大于n直接返回结束递归
#include<iostream> #include<cstring> #include<cstdio> using namespace std; int n, k; char Map[10][10]; int v[10]; int sum, num; void dfs(int x) { if(num == k){sum++; return;} if(x > n)return; for(int i = 0; i < n; i++) if(Map[x][i] == '#' && !v[i]) { v[i] = 1; num ++; dfs(x + 1); num--; v[i] = 0; } dfs(x + 1); } int main() { while(cin >> n >> k) { memset(Map, 0, sizeof(Map)); if(n == -1 && k == -1)break; for(int i = 0; i < n; i++)cin >> Map[i]; memset(v, 0, sizeof(v)); sum = num =0; dfs(0); cout<<sum<<endl; } }
Q2:POJ-2251
题意:
在一个立体空间, 输入三个数,L,R,C,代表有L个平面,R行,C列,.代表可以走,#代表不能走,S代表开始点,E代表结束点,问从S开始走,对每个位置,有六个走法,即空间的六个方向的走法(上下东南西北),一分钟可以走一个点,问从S走到E点,最少可以经过多少分钟,若不能到达,则输出Trapped!
思路:
简单BFS运用,只是把普通的二维平面变成了三维立体,由四个方向变成了六个方向
#include<iostream> #include<queue> #include<cstring> using namespace std; char Map[30][30][30]; int visit[30][30][30]; int dir[6][3]={1,0,0,-1,0,0,0,1,0,0,-1,0,0,0,1,0,0,-1}; struct node { int l,x,y,s; node(int ll,int xx,int yy,int ss):l(ll),x(xx),y(yy),s(ss){} }; int main() { int l,x,y; int s1,s2,s3,c1,c2,c3; while(cin>>l>>x>>y) { if(!l&&!x&&!y)break; memset(visit,0,sizeof(visit)); memset(Map,0,sizeof(Map)); for(int i=0;i<l;i++) { for(int j=0;j<x;j++)cin>>Map[i][j]; } for(int i=0;i<l;i++) for(int j=0;j<x;j++) for(int k=0;k<y;k++) { if(Map[i][j][k]=='S') { s1=i;s2=j;s3=k; } if(Map[i][j][k]=='E') { c1=i;c2=j;c3=k; } } queue<node>q; q.push(node(s1,s2,s3,0)); visit[s1][s2][s3]=1; for(;;) { if(q.empty()) { cout<<"Trapped!"<<endl; break; } node a=q.front(); //cout<<a.l<<" "<<a.x<<" "<<a.y<<endl; if(a.l==c1&&a.x==c2&&a.y==c3) { cout<<"Escaped in "<<a.s<<" minute(s)."<<endl; break; } for(int i=0;i<6;i++) { 4000 int cnt1=a.l+dir[i][0]; int cnt2=a.x+dir[i][1]; int cnt3=a.y+dir[i][2]; if(cnt1>=0&&cnt1<l&&cnt2>=0&&cnt2<x&&cnt3>=0&&cnt3<y&&!visit[cnt1][cnt2][cnt3]&&Map[cnt1][cnt2][cnt3]!='#') { visit[cnt1][cnt2][cnt3]=1; q.push(node(cnt1,cnt2,cnt3,a.s+1)); } } q.pop(); } } return 0; }
Q3:POJ-1426
题意:
给你一个[1,200]之间的整数n,要你求它的一个非0倍数m,这个m的十进制数只包含0和1.m不超过100位.
思路:
由于本题的数只有0和1构成,自然就想到了自己构造这个符合要求的数。所以这里我用DFS来构造这个数。虽然本题说最终结果数<=100位,但是经过测试本题测试数据中需要构造的数在unsigned long long 范围内有解,所以下面我用unsigned long long来表示需要构造的数。(并没有用高精度大整数)
DFS构造过程很简单了,就是每层循环向个位添加一个0或1即可。但是记得如果找到了一个合法的数要及时退出所有DFS递归函数。
#include<iostream> #include<cstdio> using namespace std; typedef unsigned __int64 ll; bool s; void dfs(ll x,int n,int k) { if(s)return; if(x%n==0) { printf("%I64u\n",x); s=true; return ; } if(k==19)return; dfs(x*10,n,k+1); dfs(x*10+1,n,k+1); } int main() { int n; while(cin>>n) { if(!n)break; s=false; dfs(1,n,0); } return 0; }
Q4:POJ-3087
题意:
给定长度都为C两个字符串,S1,S2,和一个要求的结果字符串S12。先把 S2 的最下面一张牌放在最下面,然后S1,S2交错的叠放,得到新的S12,再把S12最下面的C个字符赋值给S1,把剩下的赋值给S2,再次重复上面的过程。最后求出要得到目标字符串S,问最少需要几步。
思路:
直接BFS模拟,将下一步可得的结果放入队列中(题目所给出的输入是从低向上排列的。)
#include<string> #include<iostream> #include<queue> #include<map> using namespace std; int n; map<string,int>ant; string answer; string f(string s1,string s2) { string s12; for(int i=0;i<n;i++) { s12+=s2[i]; s12+=s1[i]; } return s12; } int bfs(string s1,string s2) { ant.clear(); string s12=f(s1,s2); ant[s12]=1; queue<string>q; q.push(s12); while(!q.empty()) { string s=q.front(); s1.clear(); s2.clear(); q.pop(); if(s==answer)return ant[s]; for(int i=0;i<n;i++)s1+=s[i]; for(int i=n;i<2*n;i++)s2+=s[i]; s12=f(s1,s2); if(ant.find(s12)!=ant.end())return -1; ant[s12]=ant[s]+1; q.push(s12); } return -1; } int main() { int k; cin>>k; for(int i=1;i<=k;i++) { cin>>n; string s1,s2; cin>>s1>>s2; cin>>answer; cout<<i<<" "<<bfs(s1,s2)<<endl; } return 0; }
Q5:POJ-3414
题意:
给你两个容器 A B 问是否能够经过有限的步骤倒水,得到容量为 C 的水
输出最小的步数,同时输出每一步的操作。
如果不能达到目标状态,则输出 impossible
思路:
总状态只有那么多, 反正每一步后都只有 6 种操作明显的 BFS 关键是每一步路径的记录。
开始用 BFS + 容器做了一遍,发现还是无法处理好输出路径问题,只好重新开始用数组模拟。
容器虽然很好用又方便,但是在不考虑内存的状况下,效率终究比不上数组模拟的了。
注意到 A 和 B 的范围是 1 到 100 的整数,
那么我们可以用vis[i][j]来记录每一种状态 0 <= i, j <= 100 ;
i 表示目前 A 容器中的水, j 表示目前 B 容器中的水
应该很容易就能分析出,对应于每一种状态的下一步只有六种情况:
一:用水池中的水装满 A
二:用水池中的水装满 B
三:把 A 中的水全部倒进废水池
四:把 B 中的水全部倒进废水池
五:把 A 中的水倒进 B 【不能溢出】
那么对应可能会有两种状态:用 k1 表示 A 中的水, k2 表示 B 中的水
如果 k1+k2 <= B 则 k2 = k1+k2; k1 = 0 【不能够装满容器 B】注意顺序
否则 k1 = k1+k2-B; k2 = B 【能够装满容器 B】
六:把 B 中的水倒进 A 【不能溢出】
也有两种情况,分析同上
如果 k1+k2 <= A 则 k1 = k1+k2; k2 = 0;
否则 k2 = k1+k2-A; k1 = A
用结构体数组来模拟队列
用 k1,k2 来记录当前容器中水的状态
前面已经分析过对应于每种情况只有 6 种操作, 那么对应每种情况的操作记录为 1 到 6 输出时处理下就好了。
当然少不了记录到当前状态最少用了多少步数 step
因为要记录路径,所以定义一个 f 来记录上一步在数组模拟队列中的下标。
最后如果能够达到目的,在判定最后一步的时候记录下最后一步在数组中的编号 lastIndex
然后从lastIndex从后往前找【f】前一个步骤在数组中的编号存在 id[] 中
最后再按照扫描出的路径依次遍历即可。
#include<iostream> #include<cstring> #include<queue> #include<string> using namespace std; struct node { int a,b,f,step;///a为第一个瓶子得水量,b为第二个,f为上一步的下标,step表示步数 string s; }pot[100000]; int visit[110][110]; int x,y,ans; string cnt[10000]; void bfs() { int head = 0, tail = 1; pot[0].a = pot[0].b = pot[0].step = 0; pot[0].f = -1; visit[0][0] = 1; while(head != tail) { if(pot[head].a == ans || pot[head].b == ans) { cout<<pot[head].step<<endl; int i = -1; while(pot[head].f != -1) { cnt[++i] = pot[head].s; head = pot[head].f; } for(;i >= 0;i--)cout<<cnt[i]<<endl; return; } if(pot[head].a < x) { node c; c.a = x; c.b = pot[head].b; c.f = head; c.step = pot[head].step + 1; c.s = "FILL(1)"; if(!visit[c.a][c.b]) { pot[tail++] = c; visit[c.a][c.b] = 1; } } if(pot[head].b < y) { node c; c.a = pot[head].a; c.b = y; c.f = head; c.step = pot[head].step + 1; c.s = "FILL(2)"; if(!visit[c.a][c.b]) { pot[tail++] = c; visit[c.a][c.b] = 1; } } if(pot[head].a) { node c; c.a = 0; c.b = pot[head].b; c.f = head; c.step = pot[head].step + 1; c.s = "DROP(1)"; if(!visit[c.a][c.b]) { pot[tail++] = c; visit[c.a][c.b] = 1; } } if(pot[head].b) { node c; c.a = pot[head].a; c.b = 0; c.f = head; c.step = pot[head].step + 1; c.s = "DROP(2)"; if(!visit[c.a][c.b]) { pot[tail++] = c; visit[c.a][c.b] = 1; } } if(pot[head].a + pot[head].b <= y) { node c; c.a = 0; c.b = pot[head].a + pot[head].b; c.f = head; c.step = pot[head].step + 1; c.s = "POUR(1,2)"; if(!visit[c.a][c.b]) { pot[tail++] = c; visit[c.a][c.b] = 1; } } if(pot[head].a + pot[head].b > y) { node c; c.a = pot[head].a + pot[head].b - y; c.b = y; c.f = head; c.step = pot[head].step + 1; c.s = "POUR(1,2)"; if(!visit[c.a][c.b]) { pot[tail++] = c; visit[c.a][c.b] = 1; } } if(pot[head].a + pot[head].b <= x) { node c; c.a = pot[head].a + pot[head].b; c.b = 0; c.f = head; c.step = pot[head].step + 1; c.s = "POUR(2,1)"; if(!visit[c.a][c.b]) { pot[tail++] = c; visit[c.a][c.b] = 1; } } if(pot[head].a + pot[head].b > x) { node c; c.a = x; c.b = pot[head].a + pot[head].b - x; c.f = head; c.step = pot[head].step + 1; c.s = "POUR(2,1)"; if(!visit[c.a][c.b]) { pot[tail++] = c; visit[c.a][c.b] = 1; } } head++; } cout<<"impossible"<<endl; } int main() { while(cin >> x >> y >> ans) { memset(visit, 0, sizeof(visit)); if(ans > x && ans > y) { cout<<"impossible"<<endl; continue; } bfs(); } }
Q6:UVA-11624
题意:
在一个矩形方阵里面,一个人要从一个位置走向另一个位置,其中某些地方有火源,每过一分钟,火源就会点燃相邻的点,同时相邻的点也变成了火源。人不能通过有火的点。问一个人能够安全地走到目的地去?最短时间多少?
思路:
Joe的起点唯一,但是起火的地方并不是唯一的,这是我们首先要明确的。
关键是之后应该怎样处理火势的蔓延与Joe逃跑这两个过程的关系,我们要清楚:只有火势可以影响Joe的逃跑路线,但Joe的逃跑路线绝对不能影响火势,所以这两个过程不可能出现在同一个BFS中。
可以这样想:既然火势的蔓延时不随人的主观意愿而改变的,那么我们可以先让火势肆意蔓延,看它到底能烧到哪里,以及烧到某个地方所需要的时间,这样,主人公在逃跑的过程中,只要在火势到达之前赶到某个地方就可以了。
综上,需要两个BFS,第一个计算火势蔓延到任意一点所需要的时间,如果火势永远到达不了某些点,就把这些点的时间设为正无穷,之后再搜索Joe的逃跑路线,条件要增加时间这一项,只要Joe能到达迷宫的边界,就算逃出来了。
#include<iostream> #include<cstring> #include<cstdio> #include<queue> #include<algorithm> using namespace std; char Map[1010][1010]; bool v[1010][1010]; int ans[1010][1010]; int dir[4][2] = {1,0,0,1,-1,0,0,-1}; struct Node { int x, y, step; Node(int xx, int yy, int ss):x(xx),y(yy),step(ss){} }; int n, m, x0, y0; queue<Node>q; bool judge(int x, int y) { return (x >= 0 && x < n && y >= 0 && y < m && !v[x][y]); } void bfs() { for(int i = 0; i < n; i++) { for(int j = 0; j < m; j++)ans[i][j] = 1 << 30; }///有可能火到不了一些地方,先把ans设置成无穷大 while(!q.empty()) { Node a = q.front(); q.pop(); for(int i = 0; i < 4; i++) { int x = a.x + dir[i][0]; int y = a.y + dir[i][1]; if(judge(x, y) && Map[x][y] != '#') { v[x][y] = 1; q.push(Node(x, y, a.step + 1)); ans[x][y] = a.step + 1; } } } memset(v, 0, sizeof(v)); q.push(Node(x0, y0, 1)); v[x0][y0] = 1; while(!q.empty()) { Node a = q.front(); q.pop(); if(a.x == 0 || a.x == n - 1 || a.y == 0 || a.y == m - 1) { cout<<a.step<<endl; return ; } for(int i = 0; i < 4; i++) { int x = a.x + dir[i][0]; int y = a.y + dir[i][1]; if(judge(x, y) && Map[x][y] == '.' && a.step + 1 <= ans[x][y]) { v[x][y] = 1; q.push(Node(x, y, a.step + 1)); } } } cout<<"IMPOSSIBLE"<<endl; } int main() { int T; cin >> T; while(T--) { while(!q.empty())q.pop(); memset(Map, 0, sizeof(Map)); memset(v, 0, sizeof(v)); cin >> n >> m; for(int i = 0; i < n; i++) { cin >> Map[i]; for(int j = 0; j < m; j++) { if(Map[i][j] == 'J') { x0 = i; y0 = j; } if(Map[i][j] == 'F') { v[i][j] = 1; q.push(Node(i, j, 0)); } } } bfs(); /* for(int i = 0; i < n; i++) { for(int j = 0; j < m; j++) cout<<ans[i][j]<< " "; cout<<endl; }*/ } return 0; }
Q7:POJ-3984
题意:
中文题
思路:
反正就是简单的结构体套结构体存一下父节点就行,由于记录路径,这里直接用数组代替队列
#include<iostream> #include<cstring> #include<cstdio> using namespace std; struct node { int x,y,f; }a[30]; int dir[4][2]={1,0,0,1,-1,0,0,-1}; int visit[6][6]; int lode[25][2]; int main() { int Map[5][5]; for(int i=0;i<5;i++) for(int j=0;j<5;j++)cin>>Map[i][j]; a[0].x=a[0].y=0;a[0].f=-1; visit[0][0]=1; int head=0;int tail=1; while(head!=tail) { if(a[head].x==4&&a[head].y==4) { int i=0; while(a[head].f!=-1) { lode[i][0]=a[head].x; lode[i][1]=a[head].y; i++; head=a[head].f; } lode[i][0]=lode[i][1]=0; for(;i>=0;i--) { printf("(%d, %d)\n",lode[i][0],lode[i][1]); } break; } for(int i=0;i<4;i++) { int x=a[head].x+dir[i][0]; int y=a[head].y+dir[i][1]; if(x>=0&&x<5&&y>=0&&y<5&&!visit[x][y]&&Map[x][y]==0) { a[tail].x=x; a[tail].y=y; a[tail].f=head; visit[x][y]=1; tail++; } } head++; } return 0; }
Q8:HDU-1241
题意:
就是给你一个地图,找出所有不相连(八个方向)的@组合有多少个
思路:
先对整个地图进行遍历,找到一个入口,然后用DFS深搜,相连的@都找到,并且将其标记为1,再找下一个入口,再DFS能够到达的所有@标记为2,最后的数字就是油田的数量。
#include<iostream> #include<cstring> #include<cstdio> using namespace std; char Map[110][110]; int dir[8][2]={0,1,1,0,0,-1,-1,0,1,1,1,-1,-1,1,-1,-1}; int m,n; int visit[110][110]; int num; void dfs(int i,int j) { if(visit[i][j])return; visit[i][j]=num; for(int k=0;k<8;k++) { int x=i+dir[k][0]; int y=j+dir[k][1]; if(x>=0&&x<m&&y>=0&&y<n&&Map[x][y]=='@'&&!visit[x][y])dfs(x,y); } } int main() { while(cin>>m>>n) { if(!m&&!n)break; memset(visit,0,sizeof(visit)); memset(Map,0,sizeof(Map)); getchar(); for(int i=0;i<m;i++) { for(int j=0;j<n;j++) { cin>>Map[i][j]; } getchar(); } num=0; for(int i=0;i<m;i++) { for(int j=0;j<n;j++) if(Map[i][j]=='@'&&!visit[i][j]) { num++; dfs(i,j); } } cout<<num<<endl; }return 0; }
Q9:HDU - 1495
题意:
中文题
思路:
我们有明确的初始状态(s=s,a=0,b=0)和终止状态(s=s>>1,a=s>>1,b=0) (PS:a为大号杯)
而每一步我们都有六个可选择的方向(s->a ;s->b ; a->s ; a->b ;b->s ;b->a),我们要得到最少的倒的次数,当然就是bfs咯。
#include<iostream> #include<cstring> #include<queue> using namespace std; struct node { int cnt[3],s; }; int visit[110][110][110]; int b[3],half; bool f(int x) { if(x==half)return true; else return false; } void bfs() { queue<node>q; node a; a.cnt[0]=b[0]; a.cnt[1]=a.cnt[2]=a.s=0; visit[a.cnt[0]][a.cnt[1]][a.cnt[2]]=1; q.push(a); while(!q.empty()) { a=q.front(); q.pop(); if(f(a.cnt[0])&&f(a.cnt[1])||f(a.cnt[0])&&f(a.cnt[2])||f(a.cnt[1])&&f(a.cnt[2])) { cout<<a.s<<endl; return ; } for(int i=0;i<3;i++) { if(a.cnt[i]>0) { for(int j=0;j<3;j++) { node temp=a; if(i==j)continue; if(temp.cnt[i]+temp.cnt[j]>=b[j]) { temp.cnt[i]+=temp.cnt[j]-b[j]; temp.cnt[j]=b[j]; } else { temp.cnt[j]+=temp.cnt[i]; temp.cnt[i]=0; } if(!visit[temp.cnt[0]][temp.cnt[1]][temp.cnt[2]]) { temp.s++; q.push(temp); visit[temp.cnt[0]][temp.cnt[1]][temp.cnt[2]]=1; } } } } } cout<<"NO"<<endl; } int main() { while(cin>>b[0]>>b[1]>>b[2]) { memset(visit,0,sizeof(visit)); if(b[0]+b[1]+b[2]==0)break; if(b[0]%2!=0) { cout<<"NO"<<endl; continue; } else { half=b[0]/2; bfs(); } } return 0; }
Q10:HDU - 2612
题意:
Y和M要在KFC约会,地图上有多个KFC,求在哪个KFC两人所走总距离最短,(注意KFC可以当做路)
思路:
用2次BFS,分别求出2个点到各个KFC的最短距离,然后找出和最小的即可
#include<iostream> #include<cstring> #include<queue> #include<cstdio> #include<algorithm> using namespace std; char Map[210][210]; int visit[210][210]; int sum1[210][210],sum2[210][210]; int dir[4][2]={1,0,0,1,-1,0,0,-1}; int m,n; struct node { int x,y,s; node(int xx,int yy,int ss):x(xx),y(yy),s(ss){} }; int main() { while(cin>>m>>n) { int x1,y1,x2,y2,p[5]; memset(sum1,0,sizeof(sum1)); memset(sum2,0,sizeof(sum2)); memset(Map,0,sizeof(Map)); getchar(); for(int i=0;i<m;i++) { for(int j=0;j<n;j++) { cin>>Map[i][j]; if(Map[i][j]=='Y') { p[1]=i;p[2]=j; } if(Map[i][j]=='M') { p[3]=i;p[4]=j; } } getchar(); } queue<node>q; memset(visit,0,sizeof(visit)); q.push(node(p[1],p[2],0)); visit[p[1]][p[2]]=1; while(!q.empty()) { node a=q.front(); for(int j=0;j<4;j++) { int x=a.x+dir[j][0]; int y=a.y+dir[j][1]; if(x>=0&&x<m&&y>=0&&y<n&&!visit[x][y]&&Map[x][y]!='#') { visit[x][y]=1; q.push(node(x,y,a.s+1)); sum1[x][y]=a.s+1; } } q.pop(); } memset(visit,0,sizeof(visit)); q.push(node(p[3],p[4],0)); visit[p[3]][p[4]]=1; while(!q.empty()) { node a=q.front(); for(int j=0;j<4;j++) { int x=a.x+dir[j][0]; int y=a.y+dir[j][1]; if(x>=0&&x<m&&y>=0&&y<n&&!visit[x][y]&&Map[x][y]!='#') { visit[x][y]=1; q.push(node(x,y,a.s+1)); sum2[x][y]=a.s+1; } } q.pop(); } int minx=1<<30; for(int i=0;i<m;i++) { for(int j=0;j<n;j++) { if(Map[i][j]=='@'&&sum1[i][j]&&sum2[i][j])minx=min(minx,sum1[i][j]+sum2[i][j]); } } cout<<minx*11<<endl; } return 0; }
相关文章推荐
- 搜索专题(BFS&&DFS)HDU1175-连连看
- 搜索专题(DFS&&BFS&&剪枝)HDU 1728-逃离迷宫
- 图的基本遍历算法的实现(BFS & DFS)复习
- CF793B:B Igor and his way to work(DFS & BFS)
- DFS&BFS--最大乘积
- hdu1241 Oil Deposits(dfs&&bfs)
- 【BFS && DFS】模块小结
- [DFS && BFS]poj3083
- DFS-BFS搜索专题【经典训练题】【有时间一个个做下来】
- 深度优先搜索(DFS)&广度优先搜索(BFS)
- !HDU 4101 Ali and Baba-博弈-(bfs&dfs扫描二维点)
- Graph Algorithms: Implementation& DFS& Strong Component& BFS & Dijkstra & Bellman Ford
- CH Round #72树洞[二分答案 DFS&&BFS]
- dfs && bfs
- leetcode -- Number of Islands -- DFS&BFS重点题
- DFS&BFS(链式前向星实现)
- PAT--列出连通集--dfs&bfs
- 图的遍历(最小转机数)——dfs&&bfs
- HLJU15级寒假培训dfs&bfs题解
- Leetcode bfs&dfs Binary Tree Postorder Traversal II