周报(八皇后,全排列,组合,连通块,迷宫问题)

本文深入探讨了算法复习的重要性和实践过程,包括八皇后问题的求解、连通块问题的处理、全排列与组合的计算,以及最短路径的寻找。通过具体的代码实现,展示了深度优先搜索(DFS)和广度优先搜索(BFS)的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

枯木逢春不在茂,年少且惜镜边人

因为马上要开学了,所以准备复习算法,并且做一做题
下周----------bfs dfs 动态规划 高精加法 高精阶乘 等等等等 ,最后总结一下[滑稽]

首先看看八皇后

一个如下的
6×66 \times 6
6×6 的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。

在这里插入图片描述
上面的布局可以用序列
2 4 6 1 3 52\ 4\ 6\ 1\ 3\ 5
2 4 6 1 3 5 来描述,第
ii
i 个数字表示在第
ii
i 行的相应位置有一个棋子,如下:
行号
1 2 3 4 5 61\ 2\ 3\ 4\ 5\ 6
1 2 3 4 5 6
列号
2 4 6 1 3 52\ 4\ 6\ 1\ 3\ 5
2 4 6 1 3 5
这只是棋子放置的一个解。请编一个程序找出所有棋子放置的解。
并把它们以上面的序列方法输出,解按字典顺序排列。
请输出前
33
3 个解。最后一行是解的总个数。
输入格式
一行一个正整数
nn
n,表示棋盘是
n×nn \times n
n×n 大小的。
输出格式
前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。
输入输出样例

6

输出

2 4 6 1 3 5
3 6 2 5 1 4
4 1 5 2 6 3
4

说明/提示
【数据范围】
对于
100%100%
100% 的数据,
6≤n≤136 \le n \le 13
6≤n≤13。
题目翻译来自NOCOW。
USACO Training Section 1.5

接下来请看代码

#include<stdio.h>
int a[105],r[105],l[105],ans[105],n,sum;
void dfs(int i)
{
	int j;
	if(i>n)
	{
		sum++;
		if(sum>3)		
		return ;
		for(i=1;i<=n;i++)
		printf("%d ",ans[i]);
		printf("\n");
		return ;
		
	}	
	for(j=1;j<=n;j++)
	{
		if(!a[j]&&!r[j+i]&&!l[j-i+n])
		{
			ans[i]=j;
			a[j]=1;
			r[j+i]=1;
			l[j-i+n]=1;
			dfs(i+1);
			a[j]=0;
			r[j+i]=0;
			l[j-i+n]=0;
		}
	}
}
int main()
{
	scanf("%d",&n);
	dfs(1);
	printf("%d",sum);
	return 0;
}

其实我一开始想的就是标价他的左下和下面和右下,然后不断的进行搜索,但是写了一下发现出来是乱码,看了看别人的思想,发现自己有点小问题

首先我的思想大体没有问题,但是在进行

dfs(i+1)

这个东西的时候就已经进行换列了,所以没必要进行列标记,所以要进行行标记也就是

a[i]=1;

**之后便是右下和左下了,看了个很厉害的表示
因为对角线有这样一个规则
左对角线 \ 有这样的规律

y-x=常数;

但是在x>y 的时候有会是负数那怎么办?
就平移n个单位 同时在if判断的时候也就要平移
所以不会产生错误
那么右对角线 /

x+y=常数

这样标记三处后 然后进行搜索然后进行输出就好了
最后别忘记 回溯哦~**

下面看看连通块问题

给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-islands
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

输入:
11110
11010
11000
00000
输出: 1
输入:
11000
11000
00100
00011
输出: 3
解释: 每座岛屿只能由水平和/或竖直方向上相邻的陆地连接而成。

下面请看代码

#include<stdio.h>4
int map[4][5]={{1,1,1,1,0},{1,1,0,1,0},{1,1,1,0,0},{0,0,0,0,0}};
int next[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int book[4][5];
int num;
void dfs(int x,int y,int color)
{
	int k,tx,ty;
	map[x][y]=color;
	for(k=0;k<=3;k++)
	{
		tx=x+next[k][0];
		ty=y+next[k][1];
		if(tx>=4||tx<0||ty>=5||ty<0)
		continue;
		if(book[tx][ty]==0&&map[tx][ty]==1)
		{
			book[tx][ty]=1;
			dfs(tx,ty,color);
		}
    }
	return ;
} 
int main()
{
	int i,j;
	for(i=0;i<4;i++)
	{
		for(j=0;j<5;j++)
		{
			if(map[i][j]==1)
			{
				num--;
				book[i][j]=1;
				dfs(i,j,num);
			}
		}
	}
	printf("%d",-num);
	return 0;
}

在这里插入图片描述
答案是一 是对的;
这里因为力扣不会用就写了个样例子
这里通过对每一块区域进行染色,num–从而更简洁的写出他有几块区域

for(k=0;k<=3;k++)
	{
		tx=x+next[k][0];
		ty=y+next[k][1];
		if(tx>=4||tx<0||ty>=5||ty<0)
		continue;
		if(book[tx][ty]==0&&map[tx][ty]==1)
		{
			book[tx][ty]=1;
			dfs(tx,ty,color);
		}
    }

这个部分是dfs的核心代码

另外另一组案例是这样的

int map[4][5]={{1,1,0,0,0},{1,1,0,0,0},{0,0,1,0,0},{0,0,0,1,1}};

输出结果

在这里插入图片描述

下面看看全排列,和组合

题目:
已知 nnn 个整数 x1,x2,…,xnx_1,x_2,…,x_nx1​,x2​,…,xn​,以及111个整数kkk(k<nk<nk<n)。从nnn个整数中任选kkk个整数相加,可分别得到一系列的和。例如当n=4,k=3n=4,k=3n=4,k=3,444个整数分别为3,7,12,193,7,12,193,7,12,19时,可得全部的组合与它们的和为:
3+7+12=223+7+12=223+7+12=22
3+7+19=293+7+19=293+7+19=29
7+12+19=387+12+19=387+12+19=38
3+12+19=343+12+19=343+12+19=34。
现在,要求你计算出和为素数共有多少种。
例如上例,只有一种的和为素数:3+7+19=293+7+19=293+7+19=29。

键盘输入,格式为:
n,kn,kn,k(1≤n≤20,k<n1 \le n \le 20,k<n1≤n≤20,k<n)
x1,x2,…,xn(1≤xi≤5000000)x_1,x_2,…,x_n (1 \le x_i \le 5000000)x1​,x2​,…,xn​(1≤xi​≤5000000)

屏幕输出,格式为: 111个整数(满足条件的种数)

数据

4 3
3 7 12 19

输出

1
#include<stdio.h>
int book[21];
int f(int a)
{   int i; 
	for(i=2;i<a;i++)
	{
		if(a%i==0)
		break; 
	} 
	if(a==i)
	return 1;
	else
	return 0; 
} 
int n,k;
int a[25];
int b[25];
long long ans=0;
void dfs(int m,int sum,int p)
{   
    int i; 
	if(m==k)
	{
		if(f(sum))
	     ans++;
		 return ; 
	} 
	for(i=p;i<n;i++)
	{
        book[i]=1;
		dfs(m+1,sum+a[i],i+1); 
        book[i]=0;
	} 
	return ; 
} 
int main()
{    int i; 
	scanf("%d %d",&n,&k);
	for(i=0;i<n;i++)
	scanf("%d",&a[i]); 
		dfs(0,0,0);
	printf("%d",ans);
	
} 

最后看看最短路径(迷宫问题)

#include <stdio.h>
int max=1000;
int p,q,min=999999999,n,m;
int book[51][51],a[51][51];
void dfs(int x,int y,int step)
{
    int next[4][2]=
    {
        {0,1},          //向右走
        {1,0},          //向下走
        {0,-1},         //向左走
        {-1,0}          //向山走
    };
    int tx,ty;
    //判断是否到达小哈的位置
    if (x==p&&y==q) {
        //更新最小值
        if(step<min)
            min=step;
        return;
    }
    
    //枚举4种走法
    for (int k=0; k<=3; k++) {
        //计算下一个点的坐标
        tx=x+next[k][0];
        ty=y+next[k][1];
        //判断是否越界
        if(tx<1||tx>n||ty<1||ty>m)
            continue;
        //判断该点是否为障碍物或者已经在路径中
        if (a[tx][ty]==0&&book[tx][ty]==0) {
            book[tx][ty]=1;     //标记这个点已经走过
            dfs(tx, ty, step+1);    //尝试下一个点
            book[tx][ty]=0;     //尝试结束,取消这个点的标记
        }
    }
}
int main() {
    int startx,starty;
    scanf("%d %d",&n,&m);   //n行m列
    //读入迷宫
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&a[i][j]);
    //读入起点坐标和终点坐标
    scanf("%d %d %d %d",&startx,&starty,&p,&q);
    //从起点开始搜索
    book[startx][starty]=1; //标记起点已经在路径,防止后面重复走
    dfs(startx, starty, 0);
    
    printf("%d\n",min);
    return 0;
}
 
 
 

最短路径其实就是dfs bfs的最初等的模板

好了下周复习背包 高精 还有序列,顺便做些题目。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值