Algorithm Notes Chapter 8-Search

Depth first search

Depth-first search is a search method that enumerates all complete paths to traverse all situations

Knapsack problem

Insert picture description here
Each item has two options to choose or not to choose, which is equivalent to a "crossroads", and when the total weight of a backpack is greater than V, it means that you have entered a dead end and you need to go back to the previous "crossroads".
Insert picture description here

#include<cstdio>
const int maxn = 30;
int n,V,maxValue = 0;  //物品件数n,背包容量V,最大价值maxValue
int w[maxn], c[maxn];  //w[i]每个物品重量,c[i]每个物品的价值

//DFS, index为当前处理的物品的编号
//sumW和sumC分别为当前总重量和当前总价值
void DFS(int index,int sumW, int sumC)
{
    
    
    if(index==n){
    
    //已经完成对n件物品的选择
        if(sumW <= V && sumC > maxValue)
        {
    
    
            maxValue = sumC;
        }
        return; 
    }
    DFS(index+1,sumW,sumC); //不选这个物品
    DFS(index+1,sumW+w[index],sumC+c[index]);  //选这个物品
}

int main(){
    
    
    scanf("%d%d",&n,&V);
    for(int i=0;i<n;i++)
    {
    
    
        scanf("%d",&w[i]);
    }
    for(int i=0;i<n;i++)
    {
    
    
        scanf("%d",&c[i]);
    }
    DFS(0,0,0);
    printf("%d\n",maxValue);
    return 0;
}

The time complexity of the above code is O(2 n ), the above code always updates maxValue after all n items are selected or not, but there may be some items that have not been processed after the selected item is selected. At n, the selected weight exceeds V, so the code can be improved.
Index represents the number of nodes that have been processed. At first, 0 indicates that no nodes have been processed.

#include<cstdio>
const int maxn = 30;
int n,V,maxValue = 0;  //物品件数n,背包容量V,最大价值maxValue
int w[maxn], c[maxn];  //w[i]每个物品重量,c[i]每个物品的价值

//DFS, index为当前处理的物品的编号
//sumW和sumC分别为当前总重量和当前总价值
void DFS(int index,int sumW, int sumC)
{
    
    
    if(index==n) return;
    DFS(index+1,sumW,sumC);  //不选择index+1的后的总重量和总价值
    if(sumW+w[index+1]<=V)
    {
    
    
        if(sumC+c[index+1]>maxValue) maxValue = sumC+c[index+1];
        DFS(index+1,sumW+w[index+1],sumC+c[index+1]);
    }
}

The above-mentioned method of reducing the amount of calculation through the restriction of the subject condition is called pruning

So after selecting the result, how to save the solution we got the result?

#include<cstdio>
#include<cstdlib>
#include<vector>
using namespace std;
//用一个临时的数组先放着,当价值确实更大的时候,更新给结果数组
const int maxn = 30;
int n,V,maxValue = 0;  //物品件数n,背包容量V,最大价值maxValue
int w[maxn], c[maxn];  //w[i]每个物品重量,c[i]每个物品的价值
vector<int> temp,result;  //临时数组与结果数组

//DFS, index为当前处理的物品的编号
//sumW和sumC分别为当前总重量和当前总价值
void DFS(int index,int sumW, int sumC)
{
    
    
    if(index==n) return;
    DFS(index+1,sumW,sumC); //没选index+1号这个节点
    if(sumW+w[index+1]<=V)  //选择了这个节点
    {
    
    
        temp.push_back(index+1);
        if(sumC+c[index+1]>maxValue){
    
    //如果是更好的方案,那么就更新
            maxValue = sumC+c[index+1];
            result = temp;
        } 
        DFS(index+1,sumW+w[index+1],sumC+c[index+1]);//在这条分支走结束之前是不会,
        //进行下一条语句temp.pop_back的也就是这条分支走完会回溯到最新的节点没有被选择的情况下
        temp.pop_back(); //为了不影响没有选择这个节点的那个分支,记得pop出来,因为temp是个全局变量
    }
}

int main()
{
    
    
	scanf("%d%d",&n,&V);
	for(int i=0;i<n;i++){
    
    
		scanf("%d",&w[i]);
	}
	for(int i=0;i<n;i++){
    
    
		scanf("%d",&c[i]);
	}
	DFS(0,0,0);
	printf("%d\n",maxValue);
	for(int i=0;i<result.size();i++){
    
    
		printf("%d ",result[i]);
	}
	return 0;
}

Sequence enumeration problem

Enumeration selects several numbers from N integers so that their sum is X, and try to maximize the sum of squares

#include<cstdio>
#include<cstdlib>
#include<vector>
using namespace std;

const int maxn = 100;
int n,k,x,maxSumSqu=-1,A[maxn];
vector<int> temp,ans;
//当前处理index号整数,当前已选整数个数为nowK
//当前已选整数之和为sum,当前已选整数平方和为sumSqu
void DFS(int index,int nowK,int sum,int sumSqu)
{
    
    
    if(nowK==k && sum==x)
    {
    
    
        if(sumSqu>maxSumSqu)
        {
    
    
            maxSumSqu = sumSqu;
            ans = temp;
        }
        return;
    }
    if(index==n || nowK > k || sum >x) return;
    //选index号数
    temp.push_back(A[index]);
    DFS(index+1,nowK + 1, sum+A[index],sumSqu+A[index]*A[index]);
    temp.pop_back();
    //不选index号数
    DFS(index+1,nowK,sum,sumSqu);
}

Breadth first search

The number of "blocks" in the matrix

Insert picture description here
(The part with only one 1 in the upper right corner of the above picture is also regarded as a block, so there are 4 blocks in total)

Basic idea: Enumerate the elements at each position. If it is 0, skip it. If it is 1, search for its adjacent elements to see if they are all 1.
In order to prevent going back, you can generally set a bool type array in_queue to judge each Whether this position has been enlisted in the BFS

Insert picture description here

#include<cstdio>
#include<queue>
using namespace std;
const int maxn = 100;
struct node{
    
    
    int x,y;
}Node;

int n,m;
int matrix[maxn][maxn];
bool in_queue[maxn][maxn] = {
    
    false};
int X[4] = {
    
    0,0,1,-1};
int Y[4] = {
    
    1,-1,0,0};

//判断(x,y)是否越界或者是否已经被访问过啦
bool judge(int x,int y)
{
    
    
    if(x>=n || x<0 || y>=m || y<0) return false;
    if(matrix[x][y]==0 || in_queue[x][y] == true) return false; //当前位置为0,或者(x,y)已经入队
    return true;
}

void BFS(int x,int y)
{
    
    
    queue<node> Q;
    Node.x = x,Node.y = y;
    Q.push(Node);
    in_queue[x][y] = true;
    while(!Q.empty())
    {
    
    
        node top = Q.front();
        Q.pop();
        for(int i=0;i<4;i++)
        {
    
    
            int newX = top.x + X[i];
            int newY = top.y + Y[i];
            if(judge(newX,newY))
            {
    
    
                Node.x = newX, Node.y = newY;
                Q.push(Node);
                in_queue[newX][newY] = true;
            }
        }
    }
}

int main()
{
    
    
    scanf("%d%d",&n,&m);
    for(int x=0;x<n;x++)
    {
    
    
        for(int y=0;y<m;y++)
        {
    
    
            scanf("%d",&matrix[x][y]);
        }
    }
    int ans = 0 ;//存放块数
    for(int x=0;x<n;x++)
    {
    
    
        for(int y=0;y<m;y++)
        {
    
    
            //如果元素为1并且还没有入队
            if(matrix[x][y]==1 && in_queue[x][y]==false)
            {
    
    
                ans++;
                BFS(x,y);
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}

Find the minimum number of steps in the maze

Insert picture description here
Insert picture description here
Since BFS is traversed by the order of levels, the number of traversed levels can be recorded from the starting point S, then the number of levels when reaching the end point T is the minimum number of steps from S to T that needs to be solved.
The node at the bifurcation can be regarded as Is the same layer

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;

const int maxn = 100;
struct node{
    
    
    int x,y;
    int step; //从S到该位置的最小步数,也就是层数
}S,T,Node;  //起点,终点,临时结点

int n,m;
char maze[maxn][maxn];
bool inq[maxn][maxn] = {
    
    false};
int X[4] = {
    
    0,0,1,-1};
int Y[4] = {
    
    1,-1,0,0};

bool test(int x,int y)
{
    
    
    if(x<0 || x>=n || y<0 || y>=m) return false;
    if(maze[x][y]=='*') return false;
    if(inq[x][y]==true) return false;
    return true;
}

int BFS()
{
    
    
    queue<node> q;
    q.push(S);
    while(!q.empty())
    {
    
    
        node top = q.front();
        q.pop();
        if(top.x==T.x && top.y==T.y) return top.step;
        for(int i=0;i<4;i++)
        {
    
    
            int newX = top.x+X[i];
            int newY = top.y+Y[i];
            if(test(newX,newY))
            {
    
    
                Node.x = newX,Node.y = newY;
                Node.step = top.step + 1;
                q.push(Node);
                inq[Node.x][Node.y]=true;
            }
        }
    }
    return -1;//无法到达终点
}

int main()
{
    
    
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
    {
    
    
        getchar();
        for(int j=0;j<m;j++)
        {
    
    
            maze[i][j] = getchar();
        }
        maze[i][m+1] = '\0';
    }
    scanf("%d%d%d%d",&S.x,&S.y,&T.x,&T.y);
    S.step = 0;
    printf("%d\n",BFS());
    return 0;
}

Insert picture description here
It should be noted that when using the STL queue to enqueue an element, it only creates a copy of the element and enqueues it. If the value of the element in the queue is modified, the value of the original element will not be changed.

Guess you like

Origin blog.csdn.net/weixin_44972129/article/details/110310545