搜索(洛谷)

目录

全排列问题

选书

八皇后 Checker Challenge

求细胞数量:

[USACO10OCT]Lake Counting S

扫雷游戏

拯救oibh总部

填涂颜色

海战

健康的荷斯坦奶牛 Healthy Holsteins

打开所有的灯

离开中山路

马的遍历

好奇怪的游戏

奇怪的电梯

路障

上学路线

回家

血色先锋队


全排列问题

代码1:dfs注意恢复现场,参看排列数字

#include
using namespace std;

const int N=10;
int n;
int path[N];
bool st[N];
void dfs(int u)
{
    if(u==n)
    {
        for(int i=0;i>n;
    dfs(0);
    return 0;
}

两种情况返回!

代码2:函数

#include
using namespace std;
int a[10];
int main()
{
	int n,i,j=1,k;
	cin>>n;
	for(i=1;i<=n;i++)
    {
        a[i]=n-i+1;
        j*=i;
    }
	for(i=1;i<=j;i++)
    {
        next_permutation(a+1,a+n+1);
        for(k=1;k<=n;k++)cout<<"    "<

选书

代码:dfs

#include
using namespace std;
int a[30][2],x,res;
bool b[30];

void dfs(int i)
{
	if(i>x) 
    {
        res++; //如果所有人都拿到了自己喜欢的书,方案数就加一
        return ;
    }
    else
        for(int j=0;j<=1;j++)
		if(!b[a[i][j]]) //分别判断每个人喜欢的第一本和第二本书是否被别人拿走,如果没有,就把这本书给这个人
			{
				b[a[i][j]]=1;//把这本书值为已拿过
				dfs(i+1); //递归下一人
				b[a[i][j]]=0; //恢复现场
			}
}

int main()
{
	cin>>x;
	if(x==0) //特判坑!
	{
		cout<<0;
		return 0;
	}
	for(int i=1;i<=x;i++) cin>>a[i][0]>>a[i][1];
	dfs(1);
	cout<

八皇后 Checker Challenge

代码:这道题可以参照一下皇后问题

#include 
using namespace std;
const int N = 100;
int n,res;
int path[N];
char g[N][N];
bool col[N],dg[N],udg[N];   //col[N]列,dg[N]正对角线,udg[N]反对角线

void dfs(int u)
{
    if(u==n)
    {  //找到一组方案
        res++;
        if(res<=3)
        {
            for(int i=0;i>n;
    for(int i=0;i

求细胞数量:

测试代码:

#include
using namespace std;
int n,m,ans=0;
int a[105][105];
bool used[105][105];
int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};
void dfs(int x,int y)
{
	used[x][y]=1;
	for(int i=0;i<4;i++)
	{
		int nx=x+dx[i];
		int ny=y+dy[i];
		cout<<"nx="<搜索(洛谷)_第1张图片

搜索(洛谷)_第2张图片

递归过程:

搜索(洛谷)_第3张图片

代码:

#include
using namespace std;
int n,m,ans;
const int N=110;
int a[N][N];  //a数组存输入的数
bool st[N][N];  //st数组记录当前的数是否遍历过
int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};  //四个方向
void dfs(int x,int y)
{
	st[x][y]=1;  //表示已经遍历过
	for(int i=0;i<4;i++)
	{
		int nx=x+dx[i];  //分别按上下左右四个方向进行遍历
		int ny=y+dy[i];
		if(a[nx][ny]==0 || st[nx][ny]==1) continue;   //如果已经遍历过或者当前的数为0则直接遍历下一个方向
		dfs(nx,ny);  //如果当前的数不是0且没有遍历过,则进行递归处理
	}
}
int main()
{
	cin>>n>>m;
	//memset(a,0,sizeof(a));  对数组进行初始化,全局变量默认初始值为0
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			scanf("%1d",&a[i][j]);  //用scanf读入整数的时候可以控制读入的位数
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(st[i][j]==0 && a[i][j]!=0)
			{
				dfs(i,j);
				ans++;
			}
		}
	}
	cout<

[USACO10OCT]Lake Counting S

同细胞数量

代码:

#include
using namespace std;
const int N=110;
char a[N][N];
bool st[N][N];
int res,n,m;
int nx[8]={-1,1,0,0,-1,-1,1,1};//x方向
int ny[8]={0,0,-1,1,-1,1,-1,1};//y方向
void dfs(int x,int y)
{
    st[x][y]=1;
    for(int i=0;i<8;i++)
    {
       int dx=x+nx[i],dy=y+ny[i];
       if(a[dx][dy]!='.'&&st[dx][dy]==0)dfs(dx,dy);
    }
}
int main()
{
    cin>>n>>m;

    memset(a,'.',sizeof(a));  //注意初始化
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>a[i][j];
            //scanf("%s",&a[i][j]);

    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(a[i][j]!='.'&&st[i][j]==0)
            {

                dfs(i,j);
                res++;
            }
        }
    }
    cout<

扫雷游戏

代码:dfs

#include

using namespace std;
const int N=110;
char ch;
int a[N][N];
int n,m;
int nx[8]={-1,1,0,0,-1,-1,1,1};//x方向
int ny[8]={0,0,-1,1,-1,1,-1,1};//y方向
int dfs(int x,int y)
{
    int res=0;
    for(int i=0;i<8;i++)
    {
       int dx=x+nx[i],dy=y+ny[i];
       if(a[dx][dy]==-1)res++;
    }

    return res;
}
int main()
{
    cin>>n>>m;

    memset(a,0,sizeof(a));  //注意初始化
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            cin>>ch;
            if(ch=='*')a[i][j]=-1;
            else if(ch=='?')a[i][j]=0;
        }

    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(a[i][j]==0)
            {
                a[i][j]=dfs(i,j);
                cout<

拯救oibh总部

本来以为和细胞数量思路差不多,就是在遍历查询的时候统计一下四周是否有四个*,但是样例正确,代码全错

搜索(洛谷)_第4张图片

原因是因为考虑情况不全面,并不是相邻的四周有四个*才符合条件

例如下面的样例

搜索(洛谷)_第5张图片

 其实这道题可以反过来思考就和细胞数量差不多了,dfs递归寻找出边界部分带有0的连通块,将其标记为*,最后遍历计算出剩下的0的数量即答案

搜索(洛谷)_第6张图片

代码:

#include
using namespace std;
int n,m,res;
const int N=510;
char a[N][N];  //a数组存输入的数
bool st[N][N];  //st数组记录当前的数是否遍历过
int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};  //四个方向
void dfs(int x,int y)
{
	st[x][y]=1;  //表示已经遍历过
	a[x][y]='*';  //如果是'0'就变为'*'
	for(int i=0;i<4;i++)
	{
		int nx=x+dx[i];  //分别按上下左右四个方向进行遍历
		int ny=y+dy[i];
		if(a[nx][ny]=='*' || st[nx][ny]==1) continue;   //如果已经遍历过或者当前为'*'则直接遍历下一个方向
		dfs(nx,ny);  //如果当前的数不是'0'且没有遍历过,则进行递归处理
	}
}
int main()
{
	cin>>n>>m;
	memset(a,'*',sizeof(a));  //对数组进行初始化,全局变量默认初始值为*
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
            cin>>a[i][j]; 
            
	for(int i=1;i<=n;i++)  //搜索第一列和最后一列的格子 
    {
        if(a[i][1]=='0' && st[i][1]==0) //如果有能过的就搜索
            dfs(i,1);
        if(a[i][m]=='0' && st[i][m]==0)
            dfs(i,m);
    }

    for(int i=1;i<=m;i++)  //搜索第一行和最后一行的格子
    {
        if(a[1][i]=='0' && st[1][i]==0)
            dfs(1,i);
        if(a[n][i]=='0' && st[n][i]==0)
            dfs(n,i);
    }

	for(int i=1;i<=n;i++)  //最后搜索没有被淹的格子 
        for(int j=1;j<=m;j++)
        if(a[i][j]=='0')res++;
    cout<

填涂颜色

思路和拯救oibh总部一样,但是要注意初始化,如果是将数组看成数字,会出现死循环,所以就把数组看成字符串

代码:

#include
using namespace std;
int n,m,res;
const int N=50;
char a[N][N];  //a数组存输入的数
bool st[N][N];  //st数组记录当前的数是否遍历过
int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};  //四个方向
void dfs(int x,int y)
{
	st[x][y]=1;  //表示已经遍历过
	a[x][y]='3';  //如果是'0'就变为'3',便于区分
	for(int i=0;i<4;i++)
	{
		int nx=x+dx[i];  //分别按上下左右四个方向进行遍历
		int ny=y+dy[i];
		if(a[nx][ny]=='0' && st[nx][ny]==0) dfs(nx,ny); //如果当前的数不是'0'且没有遍历过,则进行递归处理

	}

}
int main()
{
	cin>>n;
	memset(a,'1',sizeof(a));  //对数组进行初始化,全局变量默认初始值为‘1’
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
            cin>>a[i][j];

	for(int i=1;i<=n;i++)  //搜索第一列和最后一列的格子,第一行和最后一行的格子
    {
        if(a[i][1]=='0' && st[i][1]==0) //如果有能过的就搜索
            dfs(i,1);
        if(a[i][n]=='0' && st[i][n]==0)
            dfs(i,n);
        if(a[1][i]=='0' && st[1][i]==0)
            dfs(1,i);
        if(a[n][i]=='0' && st[n][i]==0)
            dfs(n,i);
    }

	for(int i=1;i<=n;i++)  //输出恢复不该变为3的0
    {
        for(int j=1;j<=n;j++)
        {
            if(a[i][j]=='0')
                a[i][j]='2';

            else if(a[i][j]=='3')
                a[i][j]='0';
            cout<

海战

理解清楚题意中的方形: 

搜索(洛谷)_第7张图片

不合法的情况,在 2*2 的矩阵中,只有这四种情况:

1.

##
#.

2.

##
.#

3.

.#
##

4.

#.
##

可以在开头时特判一下,不满足条件直接输出,否则记录一下出现了几个矩阵

如何记录矩阵?可以在搜到矩阵的左上角时,判断他的左侧和上侧是否不为#

代码:

#include
using namespace std;
const int N=1010;
char a[N][N];
int n,m,res;
bool check(int x,int y)
{
    int k=0;
    if(a[x][y]=='#')k++;
    if(a[x+1][y]=='#')k++;
    if(a[x][y+1]=='#')k++;
    if(a[x+1][y+1]=='#')k++;
    return k==3;
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
            cin>>a[i][j];
    }
    
    for(int i=1;i<=n;i++)//特殊情况的判断 
    {
        for(int j=1;j<=m;j++)
        {
            if(check(i,j))
            {
                printf("Bad placement.");
                return 0;
            }
        }
    }
    
    for(int i=1;i<=n;i++) //判断是否为矩阵,并记录答案 
    {
        for(int j=1;j<=m;j++)
        {
            if(a[i][j]=='#'&&a[i][j-1]!='#'&&a[i-1][j]!='#')res++;
        }
    }
    printf("There are %d ships.",res);
    return 0;
}

健康的荷斯坦奶牛 Healthy Holsteins

一行一行地枚举,记录到res数组中,再判断符合条件的方案

代码:

#include
using namespace std;
int v,g,a[30],b[30][30],m=20,mx[30],res[30];
bool check(int x)
{
	for(int i=1;i<=v;i++)  //枚举牛每天需要的每种维他命的最小量
	{
		int sum=0; //别忘了初始化!!!
		for(int j=1;j<=x;j++)
		{
			sum+=b[res[j]][i];//累加
		}
		if(sumg)//搜完了,不管它成功不成功我都要结束了,否则就会死循环。
	{
		if(check(z) && z>v;
	for(int i=1;i<=v;i++) cin>>a[i];
	cin>>g;
	for(int i=1;i<=g;i++)
        for(int j=1;j<=v;j++)
            cin>>b[i][j];

	dfs(1,0);  //从每一行开始搜索
	cout<

打开所有的灯

代码:dfs

#include
using namespace std;
int a[5][5],res=0,m=10;//定义变量
void dd(int x,int y)//处理按一次灯
{
    a[x][y]=1-a[x][y];      //本身
    a[x+1][y]=1-a[x+1][y];  //下
    a[x][y+1]=1-a[x][y+1];  //右
    a[x-1][y]=1-a[x-1][y];  //上
    a[x][y-1]=1-a[x][y-1];  //左
}
void dfs(int k)
{
    if(k>m) return;//限制,Mix不小于k的话会超时
    int s=0;
    for(int i=1;i<=3;i++)
      for(int j=1;j<=3;j++)
        s+=a[i][j];
    if(s==9)//判断都打开了
    {
        res=k-1;
        m=min(m,res);
    }
    //有没打开的
    for(int i=1;i<=3;i++)
      for(int j=1;j<=3;j++)
        {
            dd(i,j);
            dfs(k+1);
            dd(i,j);  //恢复现场
        }

    return;
}
int main()
{
    for(int i=1;i<=3;i++)
      for(int j=1;j<=3;j++)
        cin>>a[i][j];
    dfs(1);
    cout<

离开中山路

和走迷宫很像,只需要起点和终点设置一下,对于是否判断终点都可以

代码1:不判断

#include 
#include 
#include 
#include 
using namespace std;

const int N = 1010;
int n, m;
int g[N][N], d[N][N];
int x1,y1,x2,y2;
struct node
{
    int x,y;
};

int bfs()
{
    queueq;
    node tmp;
    tmp.x=x1-1;
    tmp.y=y1-1;
    q.push(tmp);


    memset(d, -1, sizeof d);
    d[x1-1][y1-1] = 0;

    int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};

    while (!q.empty())
    {
        node x=q.front();
        q.pop();

        for (int i = 0; i < 4; i ++ )
        {
            int u = x.x + dx[i], v = x.y + dy[i];
            tmp.x=u;tmp.y=v;

            if (u >= 0 && u < n && v >= 0 && v < n&& g[u][v] == 0 && d[u][v] == -1)
            {
                d[u][v] = d[x.x][x.y] + 1;

                q.push(tmp);
            }
        }
    }

    return d[x2-1][y2-1];
}

int main()
{
    cin >> n ;
    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < n; j ++ )
            scanf("%1d",&g[i][j]);

    cin>>x1>>y1>>x2>>y2;

    cout << bfs() << endl;

    return 0;
}

代码2:判断

#include 
#include 
#include 
#include 
using namespace std;

const int N = 1010;
int n, m;
int g[N][N], d[N][N];
int x1,y1,x2,y2;
struct node
{
    int x,y;
};

int bfs()
{
    queueq;
    node tmp;
    tmp.x=x1-1;
    tmp.y=y1-1;
    q.push(tmp);


    memset(d, -1, sizeof d);
    d[x1-1][y1-1] = 0;

    int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};

    while (!q.empty())
    {
        node x=q.front();
        q.pop();

        for (int i = 0; i < 4; i ++ )
        {
            int u = x.x + dx[i], v = x.y + dy[i];
            tmp.x=u;tmp.y=v;

            if (u >= 0 && u < n && v >= 0 && v < n&& g[u][v] == 0 && d[u][v] == -1)
            {
                d[u][v] = d[x.x][x.y] + 1;
                if(u==x2-1&&v==y2-1)return d[u][v];
                q.push(tmp);
            }

        }
    }

}

int main()
{
    cin >> n ;
    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < n; j ++ )
            scanf("%1d",&g[i][j]);

    cin>>x1>>y1>>x2>>y2;

    cout << bfs() << endl;

    return 0;
}

马的遍历

刚开始没弄懂题目的意思,原来是象棋里的马走日,所以注意八个方向的实现

搜索(洛谷)_第8张图片

代码:bfs

#include
using namespace std;
int dx[8]={-1,-2,-2,-1,1,2,2,1};
int dy[8]={2,1,-1,-2,2,1,-1,-2};//8个方向
int n,m,x,y;
int f[500][500];//存步数
bool vis[500][500];//走没走过
struct node
{
    int x,y;
};
void bfs()
{
    queue q;
    node tmp;
    f[x][y]=0;
	vis[x][y]=1;
	tmp.x=x;
	tmp.y=y;
	q.push(tmp);
	while(!q.empty())
	{
		int xx=q.front().x,yy=q.front().y;
		q.pop();//取队首并出队
		for(int i=0;i<8;i++)
		{
			int u=xx+dx[i],v=yy+dy[i];
			tmp.x=u,tmp.y=v;
			if(u<1||u>n||v<1||v>m||vis[u][v])continue;//出界或走过就不走
		    vis[u][v]=1;
		    q.push(tmp);
		    f[u][v]=f[xx][yy]+1;
		}
	}
}
int main()
{
	memset(f,-1,sizeof(f));

	cin>>n>>m>>x>>y;
    bfs();
	for(int i=1;i<=n;i++)
    {
	     for(int j=1;j<=m;j++)printf("%-5d",f[i][j]);
	     printf("\n");
    }
	return 0;
}

好奇怪的游戏

和马的遍历异曲同工

代码:bfs

#include
using namespace std;
int dx[12]={-1,-2,-2,-1,1,2,2,1,2,2,-2,-2};
int dy[12]={2,1,-1,-2,2,1,-1,-2,-2,2,-2,2};//12个方向
int n,m,x,y;
int f[500][500];//存步数
bool vis[500][500];//走没走过
struct node
{
    int x,y;
};
void bfs()
{
    queue q;
    node tmp;
    f[1][1]=0;
	vis[1][1]=1;
	tmp.x=1;
	tmp.y=1;
	q.push(tmp);
	while(!q.empty())
	{
		int xx=q.front().x,yy=q.front().y;
		q.pop();//取队首并出队
		for(int i=0;i<12;i++)
		{
			int u=xx+dx[i],v=yy+dy[i];
			tmp.x=u,tmp.y=v;
			if(u<1||u>50||v<1||v>50||vis[u][v])continue;//出界或走过就不走
		    vis[u][v]=1;
		    q.push(tmp);
		    f[u][v]=f[xx][yy]+1;
		}
	}
}
int main()
{
	memset(f,-1,sizeof(f));
    int x1,y1,x2,y2;
	cin>>x1>>y1>>x2>>y2;
    bfs();
	cout<

奇怪的电梯

代码1:dfs

#include
using namespace std;
int n,a,b,res=0x3f3f3f3f;
const int N=210;
int to[N];
bool vis[N];
void dfs(int now,int sum)//now表示当前搜到的楼层,sum表示按钮次数
{
    if(now==b) res=min(res,sum);
    if(sum>res) return;  //注意判断
    vis[now]=1;

    //不越界并且没有被搜过就搜
    if(now+to[now]<=n&&!vis[now+to[now]]) dfs(now+to[now],sum+1);
    if(now-to[now]>=1&&!vis[now-to[now]]) dfs(now-to[now],sum+1);
    vis[now]=0;//恢复现场
}
int main()
{
    cin>>n>>a>>b;
    for(int i=1;i<=n;i++) cin>>to[i];
    vis[a]=1;
    dfs(a,0);
    if(res!=0x3f3f3f3f) cout<

代码2:bfs

#include
using namespace std;
int n,a,b,to[205];
bool vis[205];
int now,sum;
struct node
{
    int id,step;
}x;//id表示楼层号,step表示按钮次数
void bfs()
{
    queue q;
    q.push((node){a,0});
    while(!q.empty()) //while(q.size())
	{
		x=q.front();
		now=x.id,sum=x.step;
		q.pop();
		if(now==b) break;
		if(now+to[now]<=n&&!vis[now+to[now]])
		{
			q.push((node){now+to[now],sum+1});
			vis[now+to[now]]=1;
		}
		if(now-to[now]>=1&&!vis[now-to[now]])
		{
			q.push((node){now-to[now],sum+1});
			vis[now-to[now]]=1;
		}
	}
	if(now==b) cout<>n>>a>>b;
	for(int i=1;i<=n;i++) cin>>to[i];
    bfs();
	return 0;
}

路障

代码:bfs

#include
using namespace std;
const int N=1000;
int n,k;
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
int zx[N*2],zy[N*2];  //zx,zy是障碍的坐标
bool s[N+10][N+10],vis[N+10][N+10],flag;  //map是地图,vis看是否被访问,flag看是否可以到达

struct node  //记录坐标和现在的时间
{
	int x,y,t;
};

void bfs(int x,int y,int t)
{
	queueq;//STL的queue虽然好打,但是它比手写的队列运行速度要慢的,差别应该也不是很大
	node now,net;
	now.x=x;now.y=y;now.t=t;
	q.push(now);

	while(!q.empty())
    {
		now=q.front();  //取出队头元素
		q.pop();  //出队
		int a=now.x;
		int b=now.y;
		int c=now.t;
		if(a==n && b==n)  //到了终点
        {
			flag=1;  //改变标志
			break;  //直接退出循环
		}

		s[zx[now.t-1]][zy[now.t-1]]=1;  //要点,障碍降落,因为t是从0开始,所以要减1
		for(int i=0;i<4;i++)  //枚举四个方向
        {
			int nx=a+dx[i];
			int ny=b+dy[i];
			if(nx>=1 && nx<=n && ny>=1 && ny<=n && s[nx][ny]==0 && vis[nx][ny]==0) //在矩阵中,无障碍,无访问
            {
				net.x=nx;net.y=ny;net.t=c+1;  //时间加加
				vis[nx][ny]=1;
				q.push(net);  //进入队列
			}
		}
	}
}
int main()
{
	cin>>k;
	while(k--)
    {
		cin>>n;
		memset(s,0,sizeof s);  //初始化!!
		memset(vis,0,sizeof vis);

		flag=0;  //看是否可以到达终点的标志

		for(int i=1;i<=2*n-2;i++)  //输入障碍
			cin>>zx[i]>>zy[i];

        vis[1][1]=1;  //起点肯定被访问了
		bfs(1,1,0);
		if(flag==1)
			cout<<"Yes"<

上学路线

代码1:手打队列,开始只过了两个测试点,请教大佬原来是q数组开小了出现越界,把q数组开的大大大大的(模拟队列)

#include 
#include 
#include 
using namespace std;

typedef pair PII;
const int N = 100;
int a,b,res,n;
int g[N][N],zx,zy;
PII q[4000000];

int bfs()
{
    int hh=0,tt=0;
    q[0]={1,1};

    int dx[2] = {1, 0}, dy[2] = {0, 1};

    while (hh<=tt)
    {
        auto t = q[hh++];
        for (int i = 0; i < 2; i ++ )
        {
            int x = t.first + dx[i], y = t.second + dy[i];
            if (x >= 1 && x <= a&& y >= 1 && y <= b&& g[x][y] == 0 )
            {
                if(x==a&&y==b)
                {
                    res++;
                    continue;
                }

                q[++tt]={x, y};
            }
        }
    }

    return res;

}
int main()
{
    cin >>a>>b;
    cin>>n;
    memset(g,0,sizeof g);
    for (int i = 0; i < n; i ++ )
    {
        cin>>zx>>zy;
        g[zx][zy]=1;
    }
    cout << bfs() << endl;

    return 0;
}

代码2:STL队列

#include 
#include 
#include 
#include
using namespace std;

typedef pair PII;
const int N = 100;
int a,b,n;
long long res;
int g[N][N], d[N][N],zx,zy;
PII q[N*N];

struct node  //记录扩展点的坐标信息
{
	int x,y;
};

int bfs()
{
    queueq;  //声明队列
    int dx[2] = {1, 0}, dy[2] = {0, 1};//扩展点横坐标的方向右下.扩展点纵坐标的方向右下

    node tmp; //中间存扩展点的变量也可以直接打{}
	tmp.x=1;
	tmp.y=1;
	q.push(tmp);  //入队
	int ans=0;
	while(!q.empty())  //当队列不空时
	{
	    node x=q.front();  //取出队列的头
		q.pop();//弹出
        for (int i = 0; i < 2; i ++ )
        {

			int u=x.x+dx[i];//更新扩展点的横坐标
			int v=x.y+dy[i]; //更新扩展点的纵坐标
			tmp.x=u;
			tmp.y=v;
            if (u >= 1 && u<=a&& v >= 1 && v <= b&& g[u][v] == 0 )
            {

                if(u==a&&v==b)
                {
                    res++;  //如果到达终点方案++
                    continue; //终点不需要入队,终点不能再继续向下扩展了
                }
                q.push(tmp);//终点不需要入队,终点不能再继续向下扩展了
            }
        }
    }

    return res;

}
int main()
{
    cin >>a>>b;
    cin>>n;
    memset(g,0,sizeof g); //初始化位置,设每个点都可以走
    for (int i = 0; i < n; i ++ )
    {
        cin>>zx>>zy;
        g[zx][zy]=1;  //初始化位置,设每个点都可以走
    }

    cout << bfs() << endl;

    return 0;
}

代码3:dfs

#include
using namespace std;
int a,b,k,x,y,sum;
bool s[20][20];//地图,初始化为全false,都不能走
void dfs(int x,int y){
    if(x==a&&y==b)//到学校了
    {
        sum++;
        return;
    }
    if(s[x][y+1]) dfs(x,y+1);//如果上面能走,走上面
    if(s[x+1][y]) dfs(x+1,y);//如果右面能走,走右面
}
int main()
{
    cin>>a>>b;
    for(int i=1;i<=a;i++){
        for(int j=1;j<=b;j++){
            s[i][j]=true;//将地图区域全变为能走的,留一个边界为false
        }
    }
    cin>>k;
    while(k--)
    {
        cin>>x>>y;//输入坐标
        s[x][y]=false;//施工不能走(话说这啥路啊,这么多施工的)
    }
    dfs(1,1);//从1,1开始深搜
    cout<

回家

自己打的dfs部分正确(64)

代码:

#include 
#include 
#include 
#include 
using namespace std;

const int N = 110;
int n, m, c=6,a1,b1,a2,b2;
int g[N][N], d[N][N];

struct node
{
    int x,y;
};

int bfs()
{
    queueq;
    node tmp;
    tmp.x=a1;
    tmp.y=b1;
    q.push(tmp);

    memset(d, -1, sizeof d);
    d[a1][b1] = 0;

    int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};

    while (!q.empty())
    {
        node x=q.front();
        q.pop();

        for (int i = 0; i < 4; i ++ )
        {
            int u = x.x + dx[i], v = x.y + dy[i];
            tmp.x=u;tmp.y=v;

            if (u >= 0 && u < n && v >= 0 && v < m && g[u][v] != 0 && d[u][v] == -1)
            {
                d[u][v] = d[x.x][x.y] + 1;
                c--;
                if(d[u][v]==4)c=6;
                q.push(tmp);
            }
        }
    }
    return d[a2][b2];
}

int main()
{
    cin >> n >> m;
    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < m; j ++ )
        {
            cin >> g[i][j];
            if(g[i][j]==2)a1=i,b1=j;
            if(g[i][j]==3)a2=i,b2=j;
            //cout<<"a1="<=0) cout << bfs() << endl;
    else cout<<"-1";
    return 0;
}

最优解需要考虑重复走过一个格子的情况

AC代码2:bfs

#include
using namespace std;

struct node //用结构体存储经过一个格子时的状态:当前格子的横纵坐标、步数以及 HP
{
    int x,y,step,HP;
};

int n,m;
int a[10][10];  //格子的种类
int vis[10][10];  //经过一个格子时的最大 HP
int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
int flag;
queue q;  //广度优先搜索需要的队列

void bfs()  //广度优先搜索
{
    while(!q.empty())
    {
        int x=q.front().x,y=q.front().y;
        int step=q.front().step,HP=q.front().HP;
        q.pop();
        if(a[x][y]==3)
        {
            cout<1)  //HP 小于或等于 1 则判定死亡
        {
            for(int i=0;i<4;i++)
            {
                int nx=x+dx[i],ny=y+dy[i];

                if(a[nx][ny]==1 || a[nx][ny]==3)  //尝试扩展的格子是空地或小 H 的家
                {
                    if(vis[nx][ny]>n>>m;
    memset(a,-1,sizeof a);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            cin>>a[i][j];
            if(a[i][j]==2)
            {
                q.push(node{i,j,0,6});  //将出发点入队
            }
        }
    }
    bfs();
    if(flag==0)puts("-1");  //搜索结束后仍没有到家,判定无解
    return 0;
}

血色先锋队

暴力出奇迹

代码:

#include
using namespace std;
const int N=1e5+10;
int a,b,n,m,xa[N],ya[N],xb[N],yb[N],res[N];
int main()
{
    cin>>n>>m>>a>>b;
    for(int i=1;i<=a;i++)cin>>xa[i]>>ya[i];
    for(int i=1;i<=b;i++)cin>>xb[i]>>yb[i];
    memset(res,127,sizeof(res));
    for(int i=1;i<=b;i++)
    {
        for(int j=1;j<=a;j++)
        {
            res[i]=min(res[i],abs(xa[j]-xb[i])+abs(ya[j]-yb[i]));
        }
        cout<

你可能感兴趣的:(洛谷,深度优先,算法,图论)