寒假训练营 搜索与图论 第1节 笔记

搜索

深度优先搜索(DFS)

以图(Graph)为例,深度优先搜索也称为深度优先周游(DFT),其具体的思想是:
先访问图中某个(未访问过的)结点v,然后选择一个v邻接到的未被访问过的结点w,再访问w,并按照同样的方法前进;当遇到一个所有邻接于它的结点都被访问过了的结点时,退回到已访问结点序列中最后一个拥有相邻结点未被访问过的结点,访问它的一个未被访问过的相邻结点u,再从u出发按相同的方式前进。当所有已被访问过的结点的相邻结点都被访问时,如果图中还有未被访问的顶点,则从另一未被访问过的顶点出发重复上述过程,直到图中所有顶点都被访问过时,周游结束。

问题示例

洛谷 p1706 全排列问题
题目描述
按照字典序输出自然数 1 到 n 所有不重复的排列,即 n 的全排列,要求所产生的任一数字序列中不允许出现重复的数字。

输入格式
一个整数 n。

输出格式
由 1∼n 组成的所有不重复的数字序列,每行一个序列。

每个数字保留 5个场宽。

#include<bits/stdc++.h>
  
using namespace std;
  
int a[10],b[10];  
int n,cnt=0;

void dfs(int i); 
int main(){  
    cin>>n;  
    memset(b,0,sizeof(b)); 
    dfs(0);  
    return 0;  
}

void dfs(int i){
    if(i==n) {  
        cnt++;  
        for(int j=1;j<=n;j++) printf("%5d",a[j]);  
        cout<<endl;  
    }  
    else{  
        for(int j=1;j<=n;j++)  
            if(!b[j]){  
                a[i+1]=j;  
                b[j]=1;  
                dfs(i+1);  
                b[j]=0;  
            }  
    }  
}

广度优先搜索(BFS)

以图为例,广度优先搜索(BFS) 是连通图的一种遍历算法。这一算法也是很多重要的图的算法的原型。其中被广泛使用的有Dijkstra单源最短路径算法和Prim最小生成树算法等,其算法都采用了和广度优先搜索类似的思想。广搜是一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。而并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。
广度优先搜索常用于解决以下两类问题
1.从某个点出发,是否可以到达指定的点。
2.从某个点出发,求到达指定的点的最短的路径。

问题示例

洛谷 p1364 医院设置
题目描述
设有一棵二叉树,如图:在这里插入图片描述

其中,圈中的数字表示结点中居民的人口。圈边上数字表示结点编号,现在要求在某个结点上建立一个医院,使所有居民所走的路程之和为最小,同时约定,相邻接点之间的距离为 1。如上图中,若医院建在1 处,则距离和 =4+12+2×20+2×40=136;若医院建在 3 处,则距离和 =81=4×2+13+20+40=81。

输入格式
第一行一个整数 n,表示树的结点数。

接下来的 nn 行每行描述了一个结点的状况,包含三个整数 w, u, ,v,其中 w 为居民人口数,u 为左链接(为 0 表示无链接),v 为右链接(为 0 表示无链接)。

输出格式
一个整数,表示最小距离和。

医院设置 
#include<bits/stdc++.h>

using namespace std;

int a[101],g[101][101];
int main()
{
	int n;
	cin >> n;
	int i,j,k,l,r;
	memset(g,1,sizeof g);
	for(i=1;i<=n;i++)
	{
		cin >> a[i] >> l >> r;
		if(l>0) g[i][l]=g[l][i]=1;
		if(r>0) g[i][r]=g[r][i]=1;
		g[i][i]=0;
	}
	for(k=1;k<=n;k++)
	 for(i=1;i<=n;i++)
	  if(i!=k)
	  for(j=1;j<=n;j++)
	  if(i!=j && j!=k)
	  {
	  	g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
	  }
	int mixn=100000000,tot;
	for(i=1;i<=n;i++)
	{
		tot=0;
		for(j=1;j<=n;j++)
		 tot = tot+g[i][j]*a[j];
		mixn=min(mixn,tot);
	}
	cout << mixn;
	return 0;
 } 

团队作业 搜索

洛谷 p1683 入门

#include<bits/stdc++.h>
using namespace std;
int n,m,sum=0;
char a[21][21];
int zx[4]={1,-1,0,0};
int zy[4]={0,0,1,-1};
void dfs(int x,int y)
{
	a[x][y]='#';
	int dx,dy;
	sum++;
    for(int i=0;i<4;i++)
    {
   	    dx=x+zx[i];
   		dy=y+zy[i];
   		if(dx>=1&&dx<=m&&dy>=1&&dy<=n&&a[dx][dy]=='.')
		{
			dfs(dx,dy);
		}
    }
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		for(int j=1;j<=n;j++)
		{
			cin>>a[i][j];
		}
	}
	for(int i=1;i<=m;i++)
    {
    	for(int j=1;j<=n;j++)
		{
			if(a[i][j]=='@')
    		{
       			dfs(i,j);
			}
		}
    }
	cout<<sum;
}

洛谷 P2036 [COCI2008-2009#2] PERKET

#include<bits/stdc++.h>
using namespace std;
int n,m,sum=0;
char a[21][21];
int zx[4]={1,-1,0,0};
int zy[4]={0,0,1,-1};
void dfs(int x,int y)
{
	a[x][y]='#';
	int dx,dy;
	sum++;
    for(int i=0;i<4;i++)
    {
   	    dx=x+zx[i];
   		dy=y+zy[i];
   		if(dx>=1&&dx<=m&&dy>=1&&dy<=n&&a[dx][dy]=='.')
		{
			dfs(dx,dy);
		}
    }
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		for(int j=1;j<=n;j++)
		{
			cin>>a[i][j];
		}
	}
	for(int i=1;i<=m;i++)
    {
    	for(int j=1;j<=n;j++)
		{
			if(a[i][j]=='@')
    		{
       			dfs(i,j);
			}
		}
    }
	cout<<sum;
}

洛谷 P1706 全排列问题

全排列问题
#include<iostream>
#include<algorithm>
using namespace std;

int main()
{
	int a[10];
	int n,jiechen = 1;
	cin >> n;
	for(int i = 1 ; i <= n ; i++)
	{
		a[i] = n-i+1;
		jiechen *= i;
	}
	for(int i = 1 ; i <= jiechen ; i++)
	{
		next_permutation(a+1,a+n+1);
		for(int j = 1 ; j <= n ; j++)
			cout<< "    " << a[j];
		cout << endl;
	}
	
	return 0;
}

洛谷 P1605 迷宫

迷宫 
#include<iostream>
 
using namespace std;

int n,m,t;
int x1,y1,x2,y2;
int maze[6][6];
bool vis[6][6];
int sum=0;
int dir[4][2]={{-1,0},{0,-1},{1,0},{0,1}};

int main()
{
    bool in(int x,int y);
    void dfs(int x,int y);
    cin >> n >> m >> t; 
    cin >> x1 >> y1 >> x2 >> y2;
    for(int i=0;i<t;i++)
    {
        int x,y;
        cin >> x >> y;
        maze[x][y]=1;
    }
    dfs(x1,y1);
    cout<<sum<<endl;
    return 0;
}

bool in(int x,int y)
{
    return x>=1&&x<=n&&y>=1&&y<=m;
}
void dfs(int x,int y)
{
    if(x==x2&&y==y2)
    {
        sum++;
    }
    vis[x][y]=1;
    for(int i=0;i<4;i++)
    {
        int tx=x+dir[i][0];
        int ty=y+dir[i][1];
        if(in(tx,ty)&&maze[tx][ty]!=1&&!vis[tx][ty])
        {
            dfs(tx,ty);
        }
    }
    vis[x][y]=0;
}

部分内容参考了一些大佬的想法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值