预备役间学习内容1

一、学习算法

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)才输出;

附代码

  1. #include <stdio.h>
  2. int main()
  3. {int n,a[10]={0},x=1,k=0;
  4.  scanf("%d",&n);
  5.  for(;x<=n;x++)
  6.  {a[x]=1;if(x<n)printf("%d+",1);else printf("%d\n",1);}
  7.  while(n!=2||a[2]-a[1]>1)
  8.  {if(a[n]-a[n-1]<=1)
  9.   {a[n-1]+=a[n];a[n]=0;n--;}
  10.   else
  11.   if(a[n]-a[n-1]<=3)
  12.   {a[n-1]++;a[n]--;}
  13.   else
  14.   {
  15.    a[n]--;
  16.    int js=a[n]/2;
  17.    a[n-1]++;
  18.    
  19.    if(js<a[n-1])k=1;
  20.        
  21.    a[n+1]=a[n]-js;
  22.    a[n]=js;
  23.    n++;
  24.   }
  25.   if(k!=1)
  26.   for(int i=1;i<=n;i++)
  27.   {if(i<n)printf("%d+",a[i]);else printf("%d\n",a[i]);}
  28.   else
  29.   k=0;
  30.  }    
  31.  return 0;
  32. }

二、迷宫

# 迷宫

## 题目描述

给定一个 $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进行顺时针的查找,看那一条路能走,就标记已走过,并继续递归,但在下一行,要               进行一个回溯的过程

附代码

  1. #include <stdio.h>
  2. int dl[100][100];
  3. int fi[4]={0,1,0,-1}; 
  4. int fj[4]={1,0,-1,0};
  5. int sum,M,N;
  6. void jslu(int i,int j,int zi,int zj,int a[100][100])
  7. {if(i==zi&&j==zj)
  8.  {sum++;
  9.   return ;    
  10.  }
  11.  else
  12.  {for(int x=0;x<4;x++)
  13.   {int hi=i+fi[x],hj=j+fj[x];
  14.    if((hi>=1&&hi<=M)&&(hj>=1&&hj<=N)&&a[hi][hj]!=1&&dl[hi][hj]==0)
  15.    {dl[hi][hj]=1;
  16.     jslu(hi,hj,zi,zj,a);
  17.        dl[hi][hj]=0;
  18.    }
  19.   }    
  20.  }    
  21. }
  22. int main()
  23. {int a[100][100]={0};
  24.  int T;
  25.  int qi,qj,zi,zj;
  26.  scanf("%d%d%d",&N,&M,&T);
  27.  scanf("%d%d%d%d",&qi,&qj,&zi,&zj);
  28.  while(T--)
  29.  {int i,j;
  30.   scanf("%d%d",&i,&j);
  31.   a[i][j]=1;
  32.  }
  33.  jslu(qi,qj,zi,zj,a);
  34.  printf("%d\n",sum);
  35.  return 0;
  36. }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值