Поиск с глубокой оптимизацией DFS
Алгоритм DFS
Мысль: продолжайте углубляться, пока не найдете решение, иначе вы не сможете продолжать
Это похоже на первый обход дерева корнем. Только не ударяйся о южную стену и не оглядывайся
模板一:
DFS(dep,..)//dep代表目前DFS的深度
{
if(找到解||走不下去)
{
...
return;
}
DFS(dep+1,..)//枚举下一种情况
}
模板二:
DFS(dep,..)
{
if(判断条件)
return;
for(扩展转态)
{
判断合法;
记录;
DFS(dep+1,...)
回溯;
}
}
График обхода DFS
1. Начиная с v0 на рисунке, посетите v0.
2. Найдите первую непосещенную соседнюю точку v0 и посетите вершину. Используя эту вершину в качестве новой, повторяйте этот шаг до тех пор, пока в только что посещенной вершине не останется непосещенных соседних точек.
3. Вернитесь к ранее посещенной вершине, в которой еще есть непосещенные соседние точки, и продолжайте посещать следующий не посещенный ведущий узел этой вершины.
4. Повторяйте шаги 2 и 3 до тех пор, пока все вершины не будут посещены и поиск не закончится.
v0-> v2-> v4-> v6-> v1-> v5-> v3
Тип вопроса DFS
Один: тип данных
Проблема с первичным кольцом
заглавие
Для числа n заключите в круг числа от 1 до n Требование: сумма двух соседних чисел является простым числом.
0 <п <20
Выход:
- Направление цифр одинаковое (то же по часовой стрелке или то же против часовой стрелки), и расположение не повторяется
- Когда есть только одно число (n == 1), выведите 1
- Случай вывода k: (k - количество групп данных), каждая группа вывода (кроме первой) имеет пустую строку перед
Идеи
Перед каждой рекурсией определите, является ли сумма первых двух чисел простым числом, поскольку это кольцо, последнее число и первое число также должны удовлетворять
До DFS можно было использовать простые числа для просеивания, находить простые числа в пределах 50, где n равно 20, а сумма двух наибольших простых чисел меньше 50
Код
#include<bits/stdc++.h>
using namespace std;
const int MAX=50;
int prime[25];//素数数组
bool vis[25]; //访问数组
int n;// 个数
int ans[MAX];//解答输出数组
void Prime_set() //筛法求素数
{
//Isprime 0、 IsNotprime 1
for(int i = 2; i<=sqrt(MAX) ;++ i)
if(prime[i] == 0)
{
for(int j = 2;i*j<=MAX;++j)
prime[i*j] = 1;
}
prime[1] = 0,vis[1]=true;//1虽然不是素数,但在此假设为0,将vis[1]设为true即不会遍历到1
}
void DFS(int depth)
{
if(prime[ans[depth-1]+ans[depth-2]]!=0) return ; //前两个数之和不是素数退出
if(depth==n+1&&prime[ans[depth-1]+ans[1]]!=0) return ; //当选到最后一个数时,第一个数和最后一个数之和不是素数时退出
if(depth==n+1) //选到最后一个数,输出
{
for(int i=1;i<=n;i++)
{
if(i==1) cout<<ans[i];
else cout<<" "<<ans[i];
}
cout<<endl;
}
for(int i=2;i<=n;i++) //把1~n按照一定顺序(DFS求得)填入数组ans
{
if(!vis[i])
{
vis[i]=true;
ans[depth]=i;
DFS(depth+1);
vis[i]=false;
}
}
}
int main(){
int t=1;
Prime_set();
while(cin>>n)
{
cout<<"Case "<<t++<<":"<<endl;
memset(vis,false,sizeof(vis));
memset(ans,0,sizeof(ans));
ans[1] = 1;//1永远是首元素
if(n==1) cout<<"1"<<endl;
else
DFS(2);//1永远是首元素,从2开始DFS ;也防止之后depth-2<0
cout<<endl;
}
return 0;
}
Описание заголовка: выберите номер
Известны n целых чисел x1, x2, ..., xn x_n x ** n и 1 целое число k (k <n). Из n целых чисел можно сложить k целых чисел, чтобы получить серию сумм соответственно. Например, когда n = 4, k = 3 и 4 целых числа равны 3, 7, 12, 19, все комбинации и их сумма:
3 + 7 + 12 = 22
3 + 7 + 19 = 29
7 + 12 + 19 = 38
3 + 12 + 19 = 34
Теперь вам нужно подсчитать, сколько видов сумм являются простыми числами.
Например, в приведенном выше примере только один вид суммы является простым: 3 + 7 + 19 = 29.
#include<bits/stdc++.h>
using namespace std;
int a[10005],sum=0,ans=0;
int n,k;
int sushu(int f)
{
for(int i=2;i*i<=f;i++)
{
if(f%i==0)
return 0;
}
return 1;
}
void dfs(int x,int y)//x表示差几个数,y表示选到a[y]
{
if(x==0)
ans+=sushu(sum);
else
{
y++;
for(int i=y;i<=n;i++)
{
sum+=a[i];
x--;
dfs(x,i);
sum-=a[i];//回溯
++x;
}
}
}
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
cin>>a[i];
dfs(k,0);
cout<<ans<<endl;
getchar();
getchar();
return 0;
}
Два: графика
Путь в матрице
Разработайте функцию, которая будет определять, существует ли путь, содержащий все символы строки в матрице.
Путь может начинаться с любой сетки в матрице, и каждый шаг может перемещать одну сетку влево, вправо, вверх и вниз по матрице.
Если путь проходит через определенную сетку в матрице, он не может впоследствии снова войти в эту сетку.
нота:
- Введенный путь не пустой;
- Все отображаемые символы представляют собой заглавные буквы английского алфавита.
Образец
matrix=
[
["A","B","C","E"],
["S","F","C","S"],
["A","D","E","E"]
]
str="BCCE" , return "true"
str="ASAE" , return "false"
КОД:
class Solution {
public:
bool hasPath(vector<vector<char>>& matrix, string &str)
{
for(int i=0;i<matrix.size();i++)
{
for(int j=0;j<matrix[i].size();j++)
{
if(dfs(matrix,str,0,i,j))//对每一个点深搜,起点不一样
return true;
}
}
return false;
}
bool dfs (vector<vector<char>>& matrix,string &str,int u,int i,int j )
{
if(matrix[i][j]!=str[u])return false;//不满足
if(u==str.size()-1)return true;//找到了一条路径满足
char t=matrix[i][j];//回溯需要
matrix[i][j]='*';
int dx[4]={0,0,-1,1},dy[4]={1,-1,0,0};//方向向量
for(int m=0;m<4;m++)
{
int a=i+dx[m],b=j+dy[m];
if (a >= 0 && a < matrix.size() && b >= 0 && b < matrix[a].size())
{
if(dfs(matrix,str,u+1,a,b))
return true;
}
}
matrix[i][j]=t;//回溯
return false;
}
};
Из лабиринта
Сяо Мин сейчас играет в игру, и лабиринт представляет собой матрицу N * M.
Начальная точка Сяо Мин обозначена буквой «S» на карте, конечная точка - буквой «E», препятствия - знаком «#», а открытые пространства - знаком «.».
Преграды не могут пройти. Если Сяо Мин сейчас находится в точке (x, y), то следующий шаг может перейти только к одной из четырех соседних сеток: (x + 1, y), (x-1, y), (x, y +1), (х, у-1);
Сяо Мин хочет знать, может ли он сейчас идти от начала до конца
Пример ввода
3 3
S..
..E
...
3 3
S##
###
##E
Пример вывода
Yes
No
Код переменного тока
#include<bits/stdc++.h>
using namespace std;
int n,m,flag=0,a,b;//flag是标记能否到达
const int MAX=510;
char s[MAX][MAX];
int dx[]={-1, 1, 0, 0}, dy[]={0, 0, -1, 1};//方向向量
void DFS(int i,int j)
{
if(flag||s[i][j]=='#'||i<0||i>=n||j<0||j>=m)//判出
return;
if(s[i][j]=='E')//到达终点
{
flag=1;
return;
}
s[i][j]='#';//走过了的路不回头
for(int e=0; e<4; e++)
DFS(i+dx[e], j+dy[e]);//继续深搜
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
flag=0;//每一组数据重新赋值为0
for(int i=0;i<n;i++)
scanf("%s",s[i]);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(s[i][j]=='S')a=i,b=j;//起点标记
DFS(a,b);
if(flag)
puts("Yes");
else
puts("No");
}
return 0;
}