dfs和bfs的常见套路

dfs

  • 迷宫问题
  • 联通块问题
  • 排列问题
  • 关于枝剪:寻找枝剪特征,以枝剪特征为依据去枝剪
    • 可行性枝剪 (上下界)
    • 最优性枝剪
    • 记忆化
  • dfs的缺陷:不达底部不罢休!

例题:

房间里放着n块奶酪。一只小老鼠要把它们都吃掉,问至少要跑多少距离?老鼠一开始在(0,0)点处。

输入:

4
1 1
1 -1
-1 1
-1 -1

输出:

7.41
#include<bits/stdc++.h>
#define maxn 100000+5
#define mst(a) memset(a,0,sizeof a)
#define ll long long
using namespace std;
//题号:
//问题:
//解法:两点之间的距离公式=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))
/*总结: 结构体重载运算符 枝剪 记忆化搜索 */
struct point
{
	double x,y;
	double operator-(const point a)
	{
		return sqrt((this->x-a.x)*(this->x-a.x)+(this->y-a.y)*(this->y-a.y));
	}
}A[20];
int vis[20];
double dis[20][20];
double minn = INF,n;

void dfs(int t,int p,double sum)
{
	if(sum>minn)return;//这个也是一个重要的枝剪 
	if(t==n)
	{
		if(sum<minn)minn = sum;
	}
	for(int i = 1;i<=n;i++)
		if(!vis[i])
		{
			if(!dis[p][i])
			{
				dis[i][p] = dis[p][i] = A[p]-A[i];  //记忆化,也可以做预处理 
			}
			vis[i] = 1;
			dfs(t+1,i,sum+dis[p][i]);
			vis[i] = 0;
		}
}
int main()
{
	ios::sync_with_stdio(false);
	cin>>n;
	mst(vis);
	mst(dis);
	A[0].x = 0,A[0].y = 0;
	for(int i = 1; i<=n; i++)
		cin>>A[i].x>>A[i].y;

	dfs(0,0,0);
	printf("%.2lf",minn);
	
	
	return 0;
}

bfs搜索

  • 最短路(权值为1)
  • 状态转移
#include<iostream>
#include<cstring>
#include<queue>
#include<stack>
#define maxn 20005
#define INF 0x3f3f3f3f
#define mst(a) memset(a,0,sizeof a)
#define ll long long

using namespace std;
struct cup
{
	//x y为杯子 
	//sp 步数 fg:flag 
	//prev:记录路径 
	int x,y;
	int sp,fg;
	cup* prev;
}t[10020];
queue<cup>Q;
stack<int>R;
int vis[150][150]; 
int a,b,k;
int ans = 0;

void bfs(int x,int y)
{
	cup c ;
	c.x = x, c.y = y;
	c.sp = 0, c.fg = 0;
	c.prev = NULL;
	vis[x][y] = 1;
	Q.push(c);
	int num = -1;
	while(!Q.empty())
	{
	// cout<<c.x<<ends <<c.y<<endl;
		num++;
		t[num] = Q.front();
		Q.pop();
		for(int i = 1; i <= 6; ++i)
		{
			switch(i)
			{
				case 1://fill a
						c.x = a;
						c.y = t[num].y;
						c.fg = 1;
						break;
					
				case 2://fill b
						c.y = b;
						c.x = t[num].x;
						c.fg = 2;
						break;
				case 3://drop a
						c.x = 0;
						c.y = t[num].y;
						c.fg = 3;
						break;
						
				case 4://drop b
						c.y = 0;
						c.x = t[num].x;
						c.fg = 4;
						break;
					
				case 5://pour a to b
						if(c.x+c.y> b)
						{
							c.y = b;
							c.x = t[num].x + t[num].y - b;
						}
						else 
						{
							c.y = t[num].y + t[num].x;
							c.x = 0;
						}
						c.fg = 5;
						break;
						
				case 6://pour b to a
						if(c.x+c.y> a)
						{
							c.x = a;
							c.y = t[num].y + t[num].x - a;
						}
						else 
						{
							c.x = t[num].x + t[num].y;
							c.y = 0;
						}
						c.fg = 6;
						break;
			}
			if(vis[c.x][c.y])continue;
			vis[c.x][c.y] = 1;
			c.sp = t[num].sp+1;
			c.prev  = &t[num];
			if(c.x == k ||c.y == k)
			{
				ans = c.sp;
				while(c.prev)
				{
					R.push(c.fg);
					c = *c.prev;
				}
				return ;
			} 
			Q.push(c);
		}
	}
	
}




void print()
{//输出路径 
	while(!R.empty())
	{
		int i = R.top();
		R.pop();
		switch(i)
		{
			case 1:cout<<"FILL(1)"<<endl;break;
			case 2:cout<<"FILL(2)"<<endl;break;
			case 3:cout<<"DROP(1)"<<endl;break;
			case 4:cout<<"DROP(2)"<<endl;break;
			case 5:cout<<"POUR(1,2)"<<endl;break;
			case 6:cout<<"POUR(2,1)"<<endl;break;
		}
	}
}
int main()
{
	ios::sync_with_stdio(false);
	cin>>a>>b>>k;
	mst(vis);
	bfs(0,0);
	if(!ans)
	{
		cout<<"impossible"<<endl;
	}
	else
	{
		cout<< ans <<endl;
		print(); 
	} 
	
	return 0;
}

点赞