一、学习算法
1、二叉树
(1)(遍历方法)前、中、后序
(要记录遍历过的节点)
前序(根左右):A B D H E I C F G
从开头出发
往左子节点去,依次往左,到底后,回溯到当前节点有右子节点时,在往右节点去
重复上面操作
中序(左根右):H D B I E A F C G
从树的左底侧出发
往上一级节点去,当当前节点有右节点时,输出根节点,在从它右侧的左最底边往上一级节点去
重复上面操作
后序(左右根):H D I E B F G C A
从树的左底侧出发
往上一级节点去,当当前节点有右节点时,先在从它右侧的左最底边往上一级节点去,到根节点时在输出本身
重复上面操作
2、并、查 集
(1)概念:对不同集合进行:元素查找、集合合并。
(2)运用树的一个存储模型,用一维数组模拟。
(3)(路径压缩:同一个集合内元素指向同一个父节点)
并:改变其中一个集合父节点指向。
进行合并操作时,通过一维数组查找两个集合的父节点,将其中一个集合的父节点,指向另一个集合的父节点
查:找到两个元素的根节点是否一样。
通过一维数组查找两个元素的父节点,是否一致
附代码(合并、路径压缩)
int zfq(int a)
{ if(fq[a]==a)return a;
fq[a]=zfq(fq[a]);
return fq[a];
}
void bcj(int x,int y)
{
int fqx=zfq(x);
int fqy=zfq(y);
if(fqx!=fqy)
{for(int i=1;i<=yu;i++)
if(fq[i]==fqx)
fq[i]=fqy;
}
}
二、刷题
1、自然数的拆分问题
# 自然数的拆分问题
## 题目描述
任何一个大于 $1$ 的自然数 $n$,总可以拆分成若干个小于 $n$ 的自然数之和。现在给你一个自然数 $n$,要求你求出 $n$ 的拆分成一些数字的和。每个拆分后的序列中的数字从小到大排序。然后你需要输出这些序列,其中字典序小的序列需要优先输出。
## 输入格式
输入:待拆分的自然数 $n$。
## 输出格式
输出:若干数的加法式子。
## 样例 #1
### 样例输入 #1
```
7
```### 样例输出 #1
```
1+1+1+1+1+1+1
1+1+1+1+1+2
1+1+1+1+3
1+1+1+2+2
1+1+1+4
1+1+2+3
1+1+5
1+2+2+2
1+2+4
1+3+3
1+6
2+2+3
2+5
3+4
```## 提示
数据保证,$1\le n\le 8$。
(1)、这题通过一维数组操作,首先给数组从下标1到n,赋1,输出一下。
(2) 、(每操作一次就输出一次注意输出格式)在从数组的右侧下标n,往左操作,看当前和左边数的差值,
<=1,a[n-1]+=a[n],a[n]=0,n--;
<=3,a[n-1]++;a[n]--;
>=4;a[n-1]++,a[n+1]=a[n]-(a[n]-1)/2,a[n]=(a[n]-1)/2;
>=4时要注意原(a[n]-1)/2>=(a[n]+1)才输出;
附代码
- #include <stdio.h>
- int main()
- {int n,a[10]={0},x=1,k=0;
- scanf("%d",&n);
- for(;x<=n;x++)
- {a[x]=1;if(x<n)printf("%d+",1);else printf("%d\n",1);}
- while(n!=2||a[2]-a[1]>1)
- {if(a[n]-a[n-1]<=1)
- {a[n-1]+=a[n];a[n]=0;n--;}
- else
- if(a[n]-a[n-1]<=3)
- {a[n-1]++;a[n]--;}
- else
- {
- a[n]--;
- int js=a[n]/2;
- a[n-1]++;
- if(js<a[n-1])k=1;
- a[n+1]=a[n]-js;
- a[n]=js;
- n++;
- }
- if(k!=1)
- for(int i=1;i<=n;i++)
- {if(i<n)printf("%d+",a[i]);else printf("%d\n",a[i]);}
- else
- k=0;
- }
- return 0;
- }
二、迷宫
# 迷宫
## 题目描述
给定一个 $N \times M$ 方格的迷宫,迷宫里有 $T$ 处障碍,障碍处不可通过。
在迷宫中移动有上下左右四种方式,每次只能移动一个方格。数据保证起点上没有障碍。
给定起点坐标和终点坐标,每个方格最多经过一次,问有多少种从起点坐标到终点坐标的方案。
## 输入格式
第一行为三个正整数 $N,M,T$,分别表示迷宫的长宽和障碍总数。
第二行为四个正整数 $SX,SY,FX,FY$,$SX,SY$ 代表起点坐标,$FX,FY$ 代表终点坐标。
接下来 $T$ 行,每行两个正整数,表示障碍点的坐标。
## 输出格式
输出从起点坐标到终点坐标的方案总数。
## 样例 #1
### 样例输入 #1
```
2 2 1
1 1 2 2
1 2
```### 样例输出 #1
```
1
```## 提示
对于 $100\%$ 的数据,$1 \le N,M \le 5$,$1 \le T \le 10$,$1 \le SX,FX \le n$,$1 \le SY,FY \le m$。
(1)、这是一个典型的要运用搜索算法,我以深搜举例,用递归去模拟
(2)、 在外部定义一个记录走过的点的数组,和方向数组
(3)、将一系列数据传给查找函数后,通if过比较当前位置是否是终点,决定递归的出口,
else进行顺时针的查找,看那一条路能走,就标记已走过,并继续递归,但在下一行,要 进行一个回溯的过程
附代码
- #include <stdio.h>
- int dl[100][100];
- int fi[4]={0,1,0,-1};
- int fj[4]={1,0,-1,0};
- int sum,M,N;
- void jslu(int i,int j,int zi,int zj,int a[100][100])
- {if(i==zi&&j==zj)
- {sum++;
- return ;
- }
- else
- {for(int x=0;x<4;x++)
- {int hi=i+fi[x],hj=j+fj[x];
- if((hi>=1&&hi<=M)&&(hj>=1&&hj<=N)&&a[hi][hj]!=1&&dl[hi][hj]==0)
- {dl[hi][hj]=1;
- jslu(hi,hj,zi,zj,a);
- dl[hi][hj]=0;
- }
- }
- }
- }
- int main()
- {int a[100][100]={0};
- int T;
- int qi,qj,zi,zj;
- scanf("%d%d%d",&N,&M,&T);
- scanf("%d%d%d%d",&qi,&qj,&zi,&zj);
- while(T--)
- {int i,j;
- scanf("%d%d",&i,&j);
- a[i][j]=1;
- }
- jslu(qi,qj,zi,zj,a);
- printf("%d\n",sum);
- return 0;
- }