bfs & dfs

题目链接:https://vjudge.net/contest/404511

1.最短路(bfs)

(1)一维最短路

D - Catch That Cow


题目大意:
在一条数轴上,奶牛和农夫分别在两个点,农夫有三种移动方式,
方式1:x -> x + 1; 方式2: x -> x - 1; 方式3 :x -> 2x。

每次移动需要1分钟,假定奶牛不会动,求农夫找到奶牛最少需要几分钟。
**分析:**用bfs,队列实现,可以找到最短路,因为队列取队首,每次都会取出队列中用时最短的那个,然后移动一次后在push进去,简单说就是先处理0分钟的,然后push进去,再处理1分钟的,push进去,再处理2分钟的。。。。。这样的话只要找到奶牛了就一定是最短的路。
注意:
1.定义结构体,保存当前位置,以及走到这里用了多长时间。
2.队列,vis的清空。
3.判断是否越界,是否来过(根据上面的分析可知,如果某点已经来过,那现在这次来这个点一定比第一次来的时候用时长)
4.这个题数据范围给的是小于100000,但是有种移动方式是*2,所以数组按照以前多开5个10个的会re,最好开200000以上。

AC 代码

#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <bitset>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>using namespace std;struct cow
{int x;//当前步数int sum;//走到这里用了多长时间
};bool vis[200000];//标记是否来过,*2,开大点
int n, k, ans = 0;
queue<cow> q;void bfs(int n,int k)
{cow u, v;//结构体初始化u.x = n;u.sum = 0;vis[u.x] = 1;q.push(u);while(!q.empty()){u = q.front();q.pop();v = u;if(k == v.x){ans = v.sum;return ;}//三种移动方式if(!vis[v.x * 2] && v.x + v.x <= 100000 ){v.x = v.x + v.x;v.sum += 1;q.push(v);vis[v.x] = 1;}v = u;if(!vis[v.x + 1] && v.x + 1 <= 100000 ){v.x += 1;v.sum += 1;q.push(v);vis[v.x] = 1;}v = u;if(!vis[v.x - 1] && v.x - 1 >= 0){v.x -= 1;v.sum += 1;q.push(v);vis[v.x] = 1;}}
}int main()
{while(~scanf("%d %d", &n, &k)){//队列,vis的清空,另外,队列可以不定义在全局,定义在bfs里这样也不需要清空while(!q.empty()){q.pop();}memset(vis, 0, sizeof(vis));bfs(n, k);printf("%d\n",ans);}return 0;
}

(2)三维最短路

C - Dungeon Master


题目大意:
你被困在一个三维地牢里,当前位置是s,出口在e,#是墙,.是路,你可以香南北东西上下6个方向移动,每层输入结束后,与下一层之间有一个空行,输出逃出地牢最少用时,如不能逃出,输出Trapped!
分析:
跟上一个题基本一个题。
注意
1.三维x,y,z三个坐标对应好了
2.输入的时候用%s一行一行输,用%c的话好像会吃回车
3.从0开始还是从1开始
4.行和列,x和y
5.判断的时候,注意.和E都是可以走的,好像有一次写的是只有.可以走导致一直没输出正确结果,其实这要判断那个不能走,不管可以走的话就可以避免这个问题。
剩下的和那个抓牛的题差不多
AC代码

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <queue>
#include <algorithm>using namespace std;char ch[34][34][34];
bool vis[34][34][34] = {0};
int L, R, C, ans;
//6个移动方向
int dx[6] = {1, 0, -1, 0, 0, 0};
int dy[6] = {0, -1, 0, 1, 0, 0};
int dz[6] = {0, 0, 0, 0, 1, -1};
int x1, y1, z1;//用来储存起点struct node
{int x, y, z;int step;
};bool judge(int x, int y, int z)
{if(x < 1 || y < 1 || z < 1 || x > C || y > R || z > L)//越界return false;else if(ch[z][y][x] == '#')//墙return false;else if(vis[z][y][x])//走过return false;elsereturn true;
}int bfs()
{node now, next;//一个结构体是当前位置,一个是下一个位置,英语好的都能看懂哈哈queue<node> q;now.x = x1;//初识化,搜索的起点,各个点坐标,步数,标记,pushnow.y = y1;now.z = z1;now.step = 0;vis[now.z][now.y][now.x] = 1;q.push(now);while(!q.empty()){now = q.front();//取队首,并pop,然后判断是否到终点q.pop();if(ch[now.z][now.y][now.x] == 'E'){ans = now.step;return ans;}for(int i = 0; i < 6; i++)//没到的话,6个方向{next.x = now.x + dx[i];next.y = now.y + dy[i];next.z = now.z + dz[i];if(!judge(next.x,next.y,next.z))continue;vis[next.z][next.y][next.x] = 1;next.step = now.step + 1;q.push(next);}}return 0;
}int main()
{while(~scanf("%d %d %d", &L, &R, &C) && L + R + C){memset(vis,0,sizeof(vis));for(int i = 1; i <= L; i++){for(int j = 1; j <= R; j++){scanf("%s",ch[i][j] + 1);for(int k = 1; k <= C; k++){if(ch[i][j][k] == 'S'){x1 = k;y1 = j;z1 = i;}}}}ans = bfs();if(ans)printf("Escaped in %d minute(s).\n",ans);elseprintf("Trapped!\n");}return 0;
}

G - 胜利大逃亡



分析:
跟上个题一样,就是多了一个比较
注意:
1.有可能这个地图是根本走不出来的,这样的情况要输出-1;
2.ans清零

AC代码


/*********每步代码的含义注释里没写,因为跟C题差不多********/
//下面的那几道最短路也是,差不多的
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>using namespace std;struct node
{int x, y, z;int step;
};bool ar[55][55][55];
bool vis[55][55][55] = {0};
int n, a, b, c, t, ans;
int dx[6] = {1, 0, -1, 0, 0, 0};
int dy[6] = {0, -1, 0, 1, 0, 0};
int dz[6] = {0, 0, 0, 0, 1, -1};bool judge(int x, int y, int z)
{if( x < 0 || y < 0 || z < 0 || x >= c || y >= b || z >= a)return true;else if(ar[z][y][x])return true;else if(vis[z][y][x])return true;elsereturn false;
}void bfs()
{memset(vis, 0, sizeof(vis));node now, next;queue<node> q;now.x = 0;now.y = 0;now.z = 0;now.step = 0;vis[now.z][now.y][now.x] = 1;q.push(now);while(!q.empty()){now = q.front();q.pop();if(now.z == a - 1 && now.y == b - 1 && now.x == c - 1){ans = now.step;return ;}for(int i = 0; i < 6; i++){next.z = now.z + dz[i];next.y = now.y + dy[i];next.x = now.x + dx[i];if(judge(next.x,next.y,next.z))continue;vis[next.z][next.y][next.x] = 1;next.step = now.step + 1;q.push(next);}}
}int main()
{scanf("%d",&n);for(int m = 1; m <= n; m++){scanf("%d %d %d %d",&a, &b, &c, &t);for(int i = 0; i < a; i++){for(int j = 0; j < b; j++){for(int k = 0; k < c; k++){scanf("%d",&ar[i][j][k]);}}}bfs();
//        if(ans <= t)
//            printf("%d\n",ans);
//        else
//            printf("-1\n");if(ans){if(ans <= t)printf("%d\n",ans);elseprintf("-1\n");}elseprintf("-1\n");memset(ar, 0, sizeof(ar));ans = 0;}return 0;
}//两次对拍,第一次发现有的地图会出不来,bfs返回值为0,这种情况应该输出-1
//第二次发现ans忘记清零惹!!!!

H - A计划


分析:
还是差不多,就是注意传送门,传过去之后要立马判断,传过去之后不能是传送门和墙
AC代码

这个没写judge看着乱乱的,以后有时间改改。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>using namespace std;struct node
{int x, y, z;int step;
};int c, n, m, t;
char ch[2][15][15];
bool vis[2][15][15];
int dx[] = {1, 0, 0, -1};
int dy[] = {0, 1, -1, 0};bool bfs()
{queue<node> q;node now, next;memset(vis, 0, sizeof(vis));now.x = 0;now.y = 0;now.z = 0;now.step = 0;q.push(now);vis[0][0][0] = 1;while(!q.empty()){now = q.front();q.pop();if(ch[now.z][now.y][now.x] == 'P' && now.step <= t)return 1;for(int i = 0; i < 4; i++){next.x = now.x + dx[i];next.y = now.y + dy[i];next.z = now.z;next.step = now.step + 1;if(next.x >= 0 && next.x < m && next.y >= 0 && next.y < n && !vis[next.z][next.y][next.x]){vis[next.z][next.y][next.x] = 1;if(ch[next.z][next.y][next.x] == '#'){next.z = 1 - next.z;if(ch[next.z][next.y][next.x] != '*' && ch[next.z][next.y][next.x] != '#' && !vis[next.z][next.y][next.x])q.push(next);}else if(ch[next.z][next.y][next.x] == '.' || ch[next.z][next.y][next.x] == 'P')q.push(next);}}}return 0;
}int main()
{scanf("%d",&c);while(c--){scanf("%d %d %d", &n, &m, &t);for(int i = 0; i < 2; i++){for(int j = 0; j < n; j++){scanf("%s",ch[i][j]);}}if(bfs())printf("YES\n");elseprintf("NO\n");}return 0;
}

2.bfs & dfs

这两道题是师哥讲的,就不多哔哔惹

A - Red and Black




题意:
先输入两个数,第一个一个代表列数n,第二个代表行数m,接下来的输入n*m的地图由 ‘.’ ‘@’ ‘#’ 构成,@是起始位置,.可以走,#不可以走,问可以走的点有几个
分析:
普通的bfs搜索,注意输入的第一个数是行,第二个数是列
AC代码

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>using namespace std;struct  node
{int x;int y;
};queue<node> q;char ch[25][25];
int a, b;
int m, n;
int dx[4] = {1, -1, 0, 0};
int dy[4] = {0, 0, 1, -1};
bool vis[25][25];
int ans = 0;bool judge(int x, int y)
{if(!vis[x][y] && x > 0 && x <= n && y > 0 && y <= m && ch[x][y] == '.')return true;elsereturn false;
}void bfs(int x, int y)
{node u, v;vis[x][y] = 1;ans++;u.x = x;u.y = y;q.push(u);while(!q.empty()){u = q.front();q.pop();for(int i = 0; i < 4; i++){v = u;v.x += dx[i];v.y += dy[i];if(judge(v.x, v.y)){ans++;q.push(v);vis[v.x][v.y] = 1;}}}
}int main()
{while(~scanf("%d %d",&m, &n) && n + m){memset(vis, 0, sizeof(vis));for(int i = 1; i <= n; i++){scanf("%s",ch[i] + 1);}ans = 0;for(int i = 1; i <= n; i++){for(int j = 1; j <= m; j++){if(ch[i][j] == '@')bfs(i,j);}}printf("%d\n",ans);}return 0;
}

这个题也可以用dfs来做

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include <queue>
#include <stack>using namespace std;int n, m;
char s[22][22];
int x, y;int ans;
int vis[22][22];int judge(int x, int y) {if (x < 1 || x > m || y < 1 || y > n)return 0;return 1;
}void bfs(int x, int y) {if (vis[x][y] == 1 || !judge(x, y) || s[x][y] == '#')return;vis[x][y] = 1;ans++;bfs(x + 1, y);bfs(x - 1, y);bfs(x, y + 1);bfs(x, y - 1);
}int main() {while (scanf("%d%d",&n,&m)!=EOF) {ans = 0;memset(vis, 0 ,sizeof vis);if (n == 0 && m == 0)break;getchar();for (int i = 1; i <= m; i++) {for (int j = 1; j <= n; j++) {scanf("%c", &s[i][j]);if (s[i][j] == '@') {x = i;y = j;}}getchar();}bfs(x, y);printf("%d\n",ans);}return 0;
}

K - Oil Deposits



题意:
找有几块大油田。

bfs AC代码

#include <bits/stdc++.h>using namespace std;const int M = (int)1e2;int n, m;
char s[M + 5][M + 5];
bool vis[M + 5][M + 5];struct node
{int x, y;
};
queue<node> q;int dx[] = {0, -1, -1, -1, 0, 1, 1, 1};
int dy[] = {1, 1, 0, -1, -1, -1, 0, 1};void bfs(int x, int y)
{node u, v;u.x = x, u.y = y;vis[u.x][u.y] = 1;q.push(u);while(!q.empty()){node u = q.front();q.pop();for(int i = 0; i < 8; ++i){v = u;v.x += dx[i], v.y += dy[i];if(v.x < 0 || v.x > n || v.y < 0 || v.y > m) continue;if(!vis[v.x][v.y] && s[v.x][v.y] == '@'){q.push(v);vis[v.x][v.y] = 1;}}}
}int main()
{while(~scanf("%d %d", &n, &m) && n + m){memset(vis, 0, sizeof(vis));for(int i = 1; i <= n; ++i) scanf("%s", s[i] + 1);int ans = 0;for(int i = 1; i <= n; ++i){for(int j = 1; j <= m; ++j){if(!vis[i][j] && s[i][j] == '@'){bfs(i, j);++ans;//注意ans增加的位置}}}printf("%d\n", ans);}return 0;
}

dfs AC代码

#include <bits/stdc++.h>
using namespace std;const int M = (int)1e2;int n, m;
char s[M + 5][M + 5];
bool vis[M + 5][M + 5];int dx[] = {0, -1, -1, -1, 0, 1, 1, 1};
int dy[] = {1, 1, 0, -1, -1, -1, 0, 1};void dfs(int x, int y)
{for(int i = 0; i < 8; ++i){int xx = x + dx[i], yy = y + dy[i];if(xx < 0 || xx > n || yy < 0 || yy > m) continue;if(!vis[xx][yy] && s[xx][yy] == '@'){vis[xx][yy] = 1;dfs(xx, yy);}}
}int main()
{while(~scanf("%d %d", &n, &m) && n + m){memset(vis, 0, sizeof(vis));for(int i = 1; i <= n; ++i) scanf("%s", s[i] + 1);int ans = 0;for(int i = 1; i <= n; ++i){for(int j = 1; j <= m; ++j){if(!vis[i][j] && s[i][j] == '@'){vis[i][j] = 1;dfs(i, j);++ans;}}}printf("%d\n", ans);}return 0;
}

3. dfs

B - 棋盘问题


分析:
用dfs搜索,从两个维度搜,dfs由 x = 0 搜到 x = n - 1,每个dfs里由y = 0 搜到 y = n - 1。

AC 代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>using namespace std;char ch[10][10];
bool vis[10];
int ans, cnt, n, k;
/*
ans有几种放法
cnt表示当前放了几枚棋子
*/
void dfs(int x)
{if(cnt == k) //当前所放棋子等于所求,则放法+1,并return{ans++;return ;}if(x == n)  return ;//x = n,说明越界了,returnfor(int i = 0; i < n ; i++)//搜y{if( !vis[i] && ch[x][i] == '#'){vis[i] = 1;cnt++;dfs(x + 1);//搜下一行cnt--;//回溯之后cnt减为0,所有被标记的点清零vis[i] = 0;}}dfs(x + 1);//这一行没有的话,搜下一行
}int main()
{while(~scanf("%d %d", &n, &k)){if(n == -1 && k == -1)break;ans = 0;cnt = 0;for(int i = 0; i < n; i++){scanf("%s", ch[i]);}dfs(0);printf("%d\n", ans);}return 0;
}

J - N皇后问题


分析:
1.用dfs, dfs由 x = 0 搜到 x = n - 1,每个dfs里再由y = 0 搜到 y = n - 1(很想b题)
2.如何标记,定义一个二维数组,第一维3个数即可,0代表横行,1代表倾角45°的斜线,2代表倾角135°的斜线,
3.对于横行他们的共同的特点是y相同,倾角45°的斜线的话,他们的截距相同,但是有的直线截距为负数,为避免这个问题,我们用n - 截距即可,135°的话同45°
4.n皇后问题,且n小于10,我们先把1到10皇后问题的结果都求出来,存在数组里,再根据输入,输出对应的答案,这样好像是可以避免前台后台之前频繁的转换,否则会TLE。

AC 代码

#include <iostream>
#include <cstdio>
#include <cstring>using namespace std;bool vis[3][100];//注意这三维各自含义
int n, x, y;
int ans[15];//存答案
int i = 0;void dfs(int x)
{if(x == n){ans[n]++;}else{for(int y = 0; y < n; y++){if(!vis[0][y] && !vis[1][n - y + x] && !vis[2][x + y]){vis[0][y] = vis[1][n - y + x] = vis[2][x + y] = 1;dfs(x + 1);vis[0][y] = vis[1][n - y + x] = vis[2][x + y] = 0;}}}
}int main()
{for(int i = 0; i <= 10; i++){n = i;memset(vis, 0, sizeof(vis));dfs(0);}while(~scanf("%d",&n) && n)printf("%d\n",ans[n]);return 0;
}

L - 变形课



分析:
每个字符串只有首字母和尾字母有用,每次输入记录首尾字母放在两个数组里,输入的时候要注意,输入之后立刻进行判断,若字符串为0则开始搜索,调用dfs,否则进行首尾字母的储存与计数。
dfs的话,进来之后首先判断ans是否为1,是则返回,否则判断当前序号字符串尾字母是否为m,是则将ans赋值为1并返回,否则遍历所有字符串找出为访问且首字母与当前字符串尾字母相同的,从此开始搜索。

AC 代码

#include <iostream>
#include <cstdio>
#include <cstring>using namespace std;int n = 0;
string s;
char sta[1050], edd[1005];
bool ans, vis[1005];void dfs(int k)
{if(ans == 1)//已找到return ;if(edd[k] == 'm'){ans = 1;return ;}for(int i = 1; i <= n; i++)//遍历寻找未访问且首尾可相连的,从此开始搜索{if(!vis[i] && sta[i] == edd[k]){vis[i] = 1;dfs(i);vis[i] = 0;//回溯取消标记}}
}int main()
{while(cin>>s){if(s[0] == '0')//判断,找到第一个b,并从此开始搜索{for(int i = 1; i <= n; i++){vis[i] = 0;}for(int i = 1; i <= n; i++){if(sta[i] == 'b'){vis[i] = 1;dfs(i);}}if(ans)printf("Yes.\n");elseprintf("No.\n");n = 0;ans = 0;}else//保存首尾字母{n++;sta[n] = s[0];edd[n] = s[s.size() - 1];}}return 0;
}

K-A Knight’s Journey

Description
整天待在方块里的骑士感到特别的无聊,于是他决定来一场说走就走的旅行。
然而他只能走日字,如右图所示,如果骑士当前在棋盘的正中央,他可以走标记有白点的八个区域。
骑士知道世界是一个列数和行数均不超过8(即8×8)的棋盘。
并且骑士有一点强迫症,如果用A-Z来表示列,1-99来表示横行,他只愿意走字典序最小的一条道路。
你能帮助勇敢的骑士制定一个适合他的旅行计划,使得他可以走遍整个棋盘吗?骑士可以在任一方块出发或者结束。
这里写图片描述
Input
第一行中有一个正整数n,代表数据有n组。
对于每组数据,都含有两个正整数p和q(1 <= p * q <= 26),代表棋盘有p行q列。
Output
每组数据首先应当输出”Scenario #i:”,i代表输出的是第i组数据的结果。
然后在一行之内输出一条可以走遍棋盘的路径,如果有多条路径可以走遍棋盘,那么输出按字典序排序第一的路径。
最后,留一个空行。若现在是最后一条数据,则不留空行。

在输出路径时,用A代表第一列,B代表第二列…以此类推。而使用1代表第一行,2代表第二行。
例如,若要表示从第一行第一列到第二行第三列,可以用字符串:A1C3来表示。
Sample Input
样例输入①:
3
1 1
2 3
4 3

样例输入②:
4
5 5
3 3
4 5
6 3
Sample Output
样例输出①:
Scenario #1:
A1

Scenario #2:
impossible

Scenario #3:
A1B3C1A2B4C2A3B1C3A4B2C4

样例输出②:
Scenario #1:
A1B3A5C4A3B1D2E4C5A4B2D1C3B5D4E2C1A2B4D5E3C2E1D3E5

Scenario #2:
impossible

Scenario #3:
A1B3C1A2B4D3E1C2D4E2C3A4B2D1E3C4A3B1D2E4

Scenario #4:
impossible
分析:

  1. 应该看到这个题就可以想到用DFS,当首先要明白这个题的意思是能否只走一遍(不回头不重复)将整个地图走完,而普通的深度优先搜索是一直走,走不通之后沿路返回到某处继续深搜。所以这个题要用到的回溯思想,如果不重复走一遍就走完了,做一个标记,算法停止;否则在某种DFS下走到某一步时按马跳的规则无路可走而棋盘还有为走到的点,这样我们就需要撤消这一步,进而尝试其他的路线(当然其他的路线也可能导致撤销),而所谓撤销这一步就是在递归深搜返回时重置该点,以便在当前路线走一遍行不通换另一种路线时,该点的状态是未访问过的,而不是像普通的DFS当作已经访问了。

  2. 如果有多种方式可以不重复走一遍的走完,需要输出按字典序最小的路径,而注意到国际象棋的棋盘是列为字母,行为数字,如果能够不回头走一遍的走完,一定会经过A1点,所以我们应该从A1开始搜索,以确保之后得到的路径字典序是最小的(也就是说如果路径不以A1开始,该路径一定不是字典序最小路径),***而且我们应该确保优先选择的方向是字典序最小的方向,即按照图片中的顺序走,先走1的方向,再走2的方向,以此类推,***这样我们最先得到的路径就是字典序最小的。
    3.注意坐标,x正方向向下,y正方向向右

AC代码

#include <iostream>
#include <cstdio>
#include <cstring>using namespace std;int xy[100][100];//记录第几步的位置,第一维表示步数,第二维只用1和2表示x,y
bool vis[100][100];
int n, p, q;
bool flag;
//字典序最小的行走方向
int dx[8] = {-1, 1, -2, 2, -2, 2, -1, 1};
int dy[8] = {-2, -2, -1, -1, 1, 1, 2, 2};bool judge(int x, int y)
{if(x >= 1 && x <= p && y >= 1 && y <= q && !vis[x][y] && !flag)return true;return false;
}void dfs(int a, int b, int step)
{//记录第step步时的位置xy[step][1] = a;xy[step][2] = b;if(step == p * q)//已走步数等于格数,即已经走完{flag = true;return ;}for(int i = 0; i < 8; i++){int next_x = a + dx[i];int next_y = b + dy[i];if(judge(next_x, next_y)){vis[next_x][next_y] = 1;dfs(next_x, next_y, step + 1);vis[next_x][next_y] = 0;//撤销该步}}
}int main()
{scanf("%d", &n);for(int m = 1; m <= n ; m++){flag = 0;scanf("%d %d", &p, &q);memset(vis, 0,sizeof(vis));vis[1][1] = 1;dfs(1, 1, 1);printf("Scenario #%d:\n", m);if(flag){for(int i = 1; i <= p * q; i++)printf("%c%d",xy[i][2] - 1 + 'A', xy[i][1]);//int转char}elseprintf("impossible");printf("\n");if(m != n)printf("\n");}return 0;
}

I - Sum It Up (数 与 和 )

Given a specified total t and a list of n integers, find all distinct sums using numbers from the list that add up to t. For example, if t=4, n=6, and the list is 4,3,2,2,1,14,3,2,2,1,1, then there are four different sums that equal 4: 4,3+1,2+2, and 2+1+1.(A number can be used within a sum as many times as it appears in the list, and a single number counts as a sum.) Your job is to solve this problem in general.
InputThe input will contain one or more test cases, one per line. Each test case contains t, the total, followed by n, the number of integers in the list, followed by n integers x1,…,xn. If n=0 it signals the end of the input; otherwise, t will be a positive integer less than 1000, n will be an integer between 1 and 12(inclusive), and x1,…,xn will be positive integers less than 100. All numbers will be separated by exactly one space. The numbers in each list appear in nonincreasing order, and there may be repetitions.
OutputFor each test case, first output a line containing ‘Sums of’, the total, and a colon. Then output each sum, one per line; if there are no sums, output the line ‘NONE’. The numbers within each sum must appear in nonincreasing order. A number may be repeated in the sum as many times as it was repeated in the original list. The sums themselves must be sorted in decreasing order based on the numbers appearing in the sum. In other words, the sums must be sorted by their first number; sums with the same first number must be sorted by their second number; sums with the same first two numbers must be sorted by their third number; and so on. Within each test case, all sums must be distince; the same sum connot appear twice.

Sample Input

4 6 4 3 2 2 1 1
5 3 2 1 1
400 12 50 50 50 50 50 50 25 25 25 25 25 25
0 0
Sample Output
Sums of 4:
4
3+1
2+2
2+1+1
Sums of 5:
NONE
Sums of 400:
50+50+50+50+50+50+25+25+25+25
50+50+50+50+50+25+25+25+25+25+25

题目意思:给一个数N,和K个数,求后面多个数之和等于N的所有情况;

解法:用DFS找出所有可能性,注意去掉相同的情况,搜索用常规dfs思路,注意去重,网上去重方法看不懂,用了自己好理解的string + stringstream + set 去重
string 利用 + 串新串
stringstream int -> string
set 去重
stringstream是个很好用的东东,不懂的小可爱们可以去看一下这篇文章https://blog.csdn.net/qq_33969563/article/details/109391029

AC 代码(1)当时在网上搜的没看懂人家是怎么去重的 = =

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;int n,len,a[20],b[20],cnt;int cmp(int a,int b)
{return a>b;
}void dfs(int x,int posa,int sum,int posb)
{int i;if(sum>n)return;if(sum == n){cnt++;for(i = 0; i<posb; i++){if(i)printf("+%d",b[i]);elseprintf("%d",b[i]);}printf("\n");}for(i = posa; i<len; i++){b[posb] = a[i];dfs(a[i],i+1,sum+a[i],posb+1);while(i+1<len && a[i] == a[i+1])//搜索完毕后,若下一个搜索的数仍与当前相同,则跳过直至不相同  i++;}
}int main()
{int i;while(~scanf("%d%d",&n,&len),n+len!=0){for(i = 0; i<len; i++)scanf("%d",&a[i]);sort(a,a+len,cmp);printf("Sums of %d:\n",n);cnt = 0;dfs(0,0,0,0);if(!cnt)printf("NONE\n");}return 0;
}

AC代码(2) 自己写的,用的是上面分析的那种方法

#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <set>using namespace std;int n, m;
bool flag = 0;
bool vis[110];
int ar[110], br[110];//ar存所有的数,br存选中的数
int kk = 0;
string str, s;
stringstream ss;
set<string> st;bool cmp(int x, int y)
{return x > y;
}void dfs(int sum, int sta)
{if(sum > n)//数大了,回溯return ;if(sum == n)//符合,标记flag,串字符串{flag = 1;ss.clear();//清空字符流,多组流入之前必清空ss<<br[0];//int 流成 stringss>>s;str = s;for(int i = 1; i < kk; i++){str = str + '+';//string 利用 + 可串新串ss.clear();ss<<br[i];ss>>s;str = str + s;}if(st.count(str) == 0)//去重,判断有无,无责输出,并插入set中{cout<<str<<endl;st.insert(str);}return ;}for(int i = sta; i < m; i++){if(!vis[i]){vis[i] = 1;br[kk++] = ar[i];dfs(sum + ar[i], i + 1);vis[i] = 0;//取消标记,并将已储存数字个数减1;kk--;}}
}int main()
{while(~scanf("%d %d",&n, &m) && n + m){flag = 0;memset(vis, 0, sizeof(vis));//数组清空kk = 0;for(int i = 0; i < m; i++){scanf("%d",&ar[i]);}sort(ar, ar + m, cmp);printf("Sums of %d:\n", n);dfs(0, 0);if(flag == 0)cout<<"NONE"<<endl;}return 0;
}

如果你觉得该文对你学习搜索有帮助,拜托点一下一键三连呗,反正又不花钱。
拜托了,这对我真的很重要。

bfs dfs 搜索入门模板题相关推荐

  1. FatMouse and Cheese HDU - 1078(记忆化搜索入门模板)

    题意: n * n的正方形格子(每个格子均放了奶酪),老鼠从(0,0)开始,每次最多移动k步,可以选择上下左右四个方向移动,下一个移动点奶酪块数量必须要大于当前点. 整理模板ing- 题目: FatM ...

  2. 小雨的矩阵(DFS三参数模板题)

    E-小雨的矩阵 题目描述 小雨有一个n×n 的矩阵,起点在(1,1),终点在(n,n),只能向下或向右走,且每次只能走 1 步. 矩阵上每个点都有一个点权a(i,j). 求走到终点的路径有多少不同的点 ...

  3. 第十一周项目实践4 BFS(广度优先搜索)基本模板

    测试时用的图是,可以使用其他类型的图代替. graph.h #ifndef GRAPH_H_INCLUDED #define GRAPH_H_INCLUDED#define MAXV 100 //最大 ...

  4. Leetcode51 n皇后 DFS+回溯(模板题)

    n皇后 链接 n皇后问题是说给定n*n的棋盘和n个皇后,求出所有合理的摆法.所谓合理的摆法是说n个皇后可以平安无事的处于棋盘上.国际象棋中皇后可以横着走.竖着走.斜着走,只要处于这些位置,皇后就会杀掉 ...

  5. POJ 2230 Watchcow 欧拉回路的DFS解法(模板题)

    Watchcow Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 9974 Accepted: 4307 Special Judg ...

  6. 程序员面试金典 - 面试题 08.10. 颜色填充(BFS/DFS)

    1. 题目 颜色填充.编写函数,实现许多图片编辑软件都支持的"颜色填充"功能. 给定一个屏幕(以二维数组表示,元素为颜色值).一个点和一个新的颜色值,将新颜色值填入这个点的周围区域 ...

  7. 搜索入门之BFS宽度优先搜索

    基础搜索入门BFS BFS全称宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型.Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽 ...

  8. 【八数码问题】基于状态空间法的知识表示与状态搜索:无信息搜索(BFS/DFS) 启发式搜索(A*)

    前言 一.问题引入 二.状态空间法 1. 知识及其表示 2. 状态空间法定义 3. 问题求解 三.基于状态空间搜索法解决八数码问题 1. 八数码问题的知识表示 2. 状态空间图搜索 1. 无信息搜索 ...

  9. 深度搜索 java_java实现的深度搜索与广度搜索算法BFS,DFS以及几种最短路径算法...

    java实现的深度搜索与广度搜索算法BFS,DFS以及几种最短路径算法 public class City { String name; int id; static int idCounter = ...

最新文章

  1. supervisord+supervisorclusterctl+supervisord-monit
  2. MFC里的GDI CDC HDC到底是什么?
  3. linux 识别文件类型,技术|Linux 中 7 个判断文件系统类型的方法
  4. Sharepoint学习笔记—error处理-- The user does not exist or is not unique.
  5. 为什么Controller层注入的是Service接口,而不是ServiceImpl实现类
  6. Mr.J-- jQuery学习笔记(三)--静态方法详解
  7. 用java实现归并,算法:JAVA实现归并排序
  8. C++中public,protected,private的区别
  9. Linux之at命令
  10. rhel6.3搭建iscsi-target服务器实战
  11. spss分析方法-方差分析
  12. 学习笔记(1):2020软考数据库系统工程师-基础知识培训视频-计算机系统--体系结构概述...
  13. Learun,一款专注于业务,不用写代码的框架
  14. BCH的51攻击与防守
  15. 玩转数据可视化之R语言ggplot2:(一)ggplot2实现箱线图、小提琴图、直方图等图形(快速入门)
  16. 图片格式WEBP全面解析
  17. [乡土民间故事_徐苟三传奇]第六回_放牛伢妙计订合同
  18. 倒立摆c语言程序设计,清华大学倒立摆控制系统实验指导书.pdf
  19. Socket,好像也挺简单,可是,真够烦
  20. linux7 显示任务,centos 7下计划任务详解之at

热门文章

  1. faiss-9: index进阶操作
  2. Windows和Mac上CSV文件的乱码解决办法。
  3. Android上如何实现矩形区域截屏
  4. 高绩效人士的四象限法则
  5. 浅谈session的domain 域名作用域
  6. 微信腾讯服务器一天多少电费,路由器工作一天消耗多少电费?说出来你都不信...
  7. 【python如何爬取视频】
  8. AndroidStudio实现简易android登录注册修改密码页面。
  9. ajax长轮询 java web_浅谈Websocket、Ajax轮询和长轮询(long polling)
  10. 程序员撩妹神器!C++代码制作烟花