实验二 递归和循环

  • 第1关:设计算法求解整数的划分问题,对给定的整数,输出划分数
  • 第2关:有重复元素的排列问题
  • 第3关:棋盘覆盖问题

第一关:设计算法求解整数的划分问题,对给定的整数,输出划分数

任务描述

将正整数n 表示成一系列正整数之和,n=n1+n2+…+nk, 其中n1>=n2>=…>=nk>=1 ,k>=1 。
正整数n 的这种表示称为正整数n 的划分。正整数n 的不同的划分个数称为正整数n 的划分数。

对给定的整数,输出对应的划分数。

相关知识

递归
分治

测试说明

平台会对你编写的代码进行测试:

测试输入:5
预期输出:
7

测试输入:6
预期输出:
11

提示:

对于样例一,可以划分的情况是:
5, 4+1, 3+2, 3+1+1, 2+2+1, 2+1+1+1, 1+1+1+1+1
故可以划分为7种

解题思路

q(n,m) 有以下五种情况

1.m=n 说明是对此数进行整数划分那么往下走也是两种情况

(1)本身n划分 +1

(2)最大划分数是n-1 故为m-1

2.m>n 说明m最大划分数大于需要划分的n数,则现在问题变成了划分n

3.m<n 说明n中最大划分数是m分为以下两种情况:

(1)q(n-m,m) n减去最大划分数,对剩下的数进行划分

(2)q(n,m-1) 剩下的划分都小于m,故改为m-1 继续进行递归

4.m=1 最大划分数为1,那么仅有1+1+……1一种情况

.n=1 需要划分的是1 就只有1种情况

代码

//整数划分
#include<stdio.h>
int partition(int n, int m);
int main() {int n;int p;//输入整数n scanf("%d",&n);p = partition(n, n);printf("%d",p);return 0;
}//整数划分递归
int partition(int n, int m) {//n为划分的数,m为划分数中最大加数if(n == 1 || m == 1) {//当n==1 时说明最大数是1 那就只能划分1这种结果//当m==1 时说明划分数最大是1 那就只能是1+1+…+1这种结果 return 1;}else if ( n < m){//当划分数小于m 说明需要最大加数已经定了,只需要将n进行自己划分return partition(n, n); }else if( n == m) {//当划分数和最大划分数相等,就代表从头开始划分//划分为包括本身,和最大数为本身-1 return partition(n, m-1) + 1; }else if(n > m){//当n>m 分为两种情况,最大数为m本身的情况和最大数为m-1的情况 return partition(n-m, m) + partition(n, m-1); }
}

第2关:有重复元素的排列问题

任务描述

设集合R={r1,r2,...,rn}是要进行排列的n个元素,其中r1,r2,...,rn可能相同。
试着设计一个算法,列出R的所有不同排列。
即,给定n以及待排的n个可能重复的元素。计算输出n个元素的所有不同排列。

输入描述

第1行是元素个数n,1<=n<=500。接下来的1行是待排列的n个元素,元素中间不要加空格。

输出格式

程序运行结束时,将计算输出n个元素的所有不同排列。最后1行中的数是排列总数。

测试说明

平台会对你编写的代码进行测试:

测试输入:
4
aacc

预期输出:
aacc
acac
acca
caac
caca
ccaa
6

思路过程

这题运用到了全排列的思想

全排列

//全排列问题 C语言
#include<stdio.h>void swap(int *a, int *b)
{int temp;temp = *a;*a = *b;*b = temp;return;
}
//全排列函数 p代表指向交换的位置 q代表到达交换的交换位置
void Perm(int list[], int p, int q)
{if( p == q-1) {for(int j = 0; j < q; j++){printf("%d ",list[j]);}printf("\n");return;}else {for(int i = p; i < q; i++ ){swap(&list[p],&list[i]);Perm(list, p+1, q);//为什么输入i不行但是 输入p+1可以?//因为输入i代表交换的哪几位位数而p代表的是在哪个位置交换 所以p是固定的 但是i不是固定的//得输入i
//          printf("%d %d\n",list[p],list[i]);swap(&list[p],&list[i]);
//          printf("%d %d\n",list[p],list[i]);}   }
}int main()
{int n; //数组长度int list[n];scanf("%d",&n); for(int i = 0; i < n; i++){scanf("%d",&list[i]);    }   Perm(list, 0, n);return 0;
} 

错误思路:

在递归的时候 把p和i弄混了 p是固定交换位置的 而i是动态的 是代表p往后交换的

此题代码

这道题就是在全排列的基础上 加上重复排序 的问题 需要检验重复排序

//重复字母的排列问题//全排列问题 C语言
#include<stdio.h>
int number = 0;
void swap(char *a, char *b)
{char temp;temp = *a;*a = *b;*b = temp;return;
}bool NoSame(char list[], int p, int i) {if( p < i) {for( ; p < i; p++){if(list[i] == list[p]) {
//              printf("\ni %d same %c \n",i, list[i]);return false;}}    }return true;
}//全排列函数 p代表指向交换的位置 q代表到达交换的交换位置
//不能单纯判断交换的字母是否相同 因为交换的字母不同 但是可能前面出现过
//所以需要一个函数来判断  我想复杂了 我以为全部都需要判断 然后需要一个二维数组去存
//其实不需要 就只要判断当前元素 和以前的元素是否重复就行
//噢我可真难过!
void Perm(char list[], int p, int q)
{if( p == q-1) {//将交换后的数组输出 for(int j = 0; j < q; j++){printf("%c",list[j]);}printf("\n");number++;return;}else {for(int i = p; i < q; i++ ){//如果判断出所交换的字母和前面字母不重复 则进行交换 否则不交换//我突然意识到第一个和第一个比较重复 ,肯定是重复的 if( NoSame(list, p, i) ) {//交换对应位置 swap(&list[p],&list[i]);//进行递归 Perm(list, p+1, q);//回溯算法 将其交换回来 swap(&list[p],&list[i]);}} }
}int main()
{int n; //数组长度char list[n];scanf("%d",&n); scanf("%s",list);        Perm(list, 0, n);printf("%d",number);return 0;
} 

错误思路

  1. 这是在全排列的基础上加上重复判断
  2. 我一开始想的是二维数组,然后对应一个字符串一个字符串判断,但这样的效率实在是太低了
  1. 然后看了别人的思路误以为是直接判断交换的字母是否和前面的字母有重复的字母 这样不可行 因为一开始这就是重复和重复的交换
  2. 结果应该是比较i和p 首先i肯定是大于p的 所以 如果在i之前的p 交换的字母没有重复的 代表其就是没有重复的。
  1. 今天教别人的时候发现 ,因为i前面的字母都比较过了,如果现在i所指的字母和前面的字母有重复的,那么说明这个字母排序就是重复的排序

第3关:棋盘覆盖问题

任务描述

在一个2k×2k个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为一特殊方格,且称该棋盘为一特殊棋盘。在棋盘覆盖问题中,要用图示的4种不同形态的L型骨牌覆盖给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖。
易知,覆盖任意一个2k×2k的特殊棋盘,用到的骨牌数恰好为(4K-1)/3。

输入格式

第一行为k(棋盘的尺寸),第二行为x,y(1<=x,y<=2^k),分别表示特殊方格所在行与列。

输出格式

共2^k行,分别表示覆盖该格的L型的编号(特殊格用0表示)。

输出要求:最小字符宽度为4,左对齐输出

样例

平台会对你编写的代码进行测试:

测试输入:
3 3 2
预期输出:
3 3 4 4 8 8 9 9
3 2 2 4 8 7 7 9
5 2 6 6 10 10 7 11
5 5 0 6 1 10 11 11
13 13 14 1 1 18 19 19
13 12 14 14 18 18 17 19
15 12 12 16 20 17 17 21
15 15 16 16 20 20 21 21

提示:

特殊骨牌的牌号为0
正常骨牌号从1开始
覆盖棋盘请严格遵循先覆盖左上角,右上角,左下角,右下脚的循序(具体可以参考算法书P21的代码及注释)

解题思路

  1. 棋盘覆盖问题实在是太难画了
  2. 核心思想就是
  1. 先设置变量

    1. 一个棋盘数组 Board[][]:(全局变量)棋盘格子数组
    2. sr sc:特殊格子的行列
  2. br bc:中心格子的行列(我把中心格子定在每一次递归最中心点的右下格子,以这个格子来判断特殊格子是在哪个区间。
  3. size:当前棋盘的大小
  4. Lsize:下一次递归棋盘的大小(用于找到中心格子和特殊格子)
  5. t:递归的轮数(在函数内可变值) 必须得用t 因为全局变量一直在变化,可是一轮的赋值是可以不用变化的
  6. title:递归的轮数(全局变量)
  7. 确定思路
    1. 首先先将棋盘划分为四个区间,再判断特殊格子是否在这四个区间里面的任一一个

      1. 如果在这个区间里,则继续下一轮递归
      2. 如果不在这个区间内,则将最靠近中心轴的格子赋值为t,则这个格子在这个区间内变为特殊格子,进入下一轮递归
  8. 一直递归到 size == 1 退出递归
  9. 需要注意
    1. 必须设置全局变量title,因为递归一轮的数值是不会变的,那么t会一直在3 2 1这三个数值轮流转,每开始一轮递归,title值加1再赋值给t,代表这是第几轮递归,第几个格子
    2. 中心格子和特殊格子是一直在变化的

错误历程1

我一开始认为 只需要传入变化的k和变化的格子数t就可以了

我以为特殊格子是不用变化的 但是每次没有找到特殊格子的区间内都需要变化

忽略了特殊格子是一直在变化的,所以必须得传入特殊格子,而我根本就没有传入特殊格子

#include<stdio.h>
#include<math.h>
#define Max 100
/*变量的定义如下sr:特殊格子的行 sc:特殊格子的列 br:划分格子的行 bc:划分格子的列Board[][]:(全局变量)棋盘格子数组t:定义划分格子的数字
*/ int Board[Max][Max] = {0};
int sr = 0;
int sc = 0;//错误思路 忽略了特殊格子是一直在变化的,所以必须得传入特俗格子,而我根本就没有传入特殊格子
void BoardCover(int k, int t)
{int br; // br:划分格子的行 int bc; //    bc:划分格子的列br = pow(2,k);bc = pow(2,k);printf("%d %d\n",br,bc); //测试输出printf("k %d\n", k);//当划分到最后只有一个格子的时候 就return if(k == 1){return; }//左上角覆盖并划分 if( sr <= br-1 && sc <= bc-1 ) {BoardCover(k-1, t+1);}else{Board[br-1][bc-1] = t;BoardCover(k-1, t+1); }//右上角覆盖并划分 if( sr <= br-1 && sc >= bc ) {BoardCover(k-1, t+1);}else{Board[br-1][bc] = t;BoardCover(k-1, t+1); }//左下角覆盖并划分 if( sr >= br && sc <= bc-1 ) {BoardCover(k-1, t+1);}else{Board[br][bc-1] = t;BoardCover(k-1, t+1); }//右下角覆盖并划分 if( sr <= br && sc <= bc ) {BoardCover(k-1, t+1);}else{Board[br][bc] = t;BoardCover(k-1, t+1); }
}int main()
{int k; //棋盘格是2^k*2^kscanf("%d %d %d",&k, &sr, &sc);int t = 0;
//  printf("%d %d",sr,sc); //测试输出Board[sr][sc] = t;BoardCover(k-1, t+1);for(int i = 0; i < pow(2,k); i++){for(int j = 0; j < pow(2,k); j++){printf("%d ",Board[i][j]);}printf("\n");}return 0;
}

错误历程2

我这次传入了特殊的格子,但是我取忽略了,中心点也是跟着特殊格子去变化的,即这整个过程是所有东西都在变化的,这个时候必须引入一个可以变化的点,可以确认中心点和特殊格子的点

#include<stdio.h>
#include<math.h>
#define Max 100
/*变量的定义如下sr:特殊格子的行 sc:特殊格子的列 br:划分格子的行 bc:划分格子的列Board[][]:(全局变量)棋盘格子数组t:定义划分格子的数字
*/ int Board[Max][Max] = {0};//错误思路 忽略了特殊格子是一直在变化的,所以必须得传入特俗格子,而我根本就没有传入特殊格子
//为什么不能只传递k 为什么进入不了下一个循环 没有办法再将其返回回去 不仅是减少也是夸大
void BoardCover(int k, int t, int sr, int sc)
{int br; // br:划分格子的行 int bc; //    bc:划分格子的列br = pow(2,k);bc = pow(2,k);
//  printf("%d %d\n",br,bc); //测试输出printf("k %d\n",k);//当划分到最后只有一个格子的时候 就return     if(k < 0){return; }  //左上角覆盖并划分 if( sr <= br-1 && sc <= bc-1 ) {BoardCover(k-1, t+1, sr, sc);}else{Board[br-1][bc-1] = t;BoardCover(k-1, t+1, br-1, bc-1); }//右上角覆盖并划分 if( sr <= br-1 && sc >= bc ) {BoardCover(k-1, t+1, sr, sc);}else{Board[br-1][bc] = t;BoardCover(k-1, t+1,  br-1, bc); }//左下角覆盖并划分 if( sr >= br && sc <= bc-1 ) {BoardCover(k-1, t+1, sr, sc);}else{Board[br][bc-1] = t;BoardCover(k-1, t+1,  br, bc-1); }//右下角覆盖并划分 if( sr >= br && sc >= bc ) {BoardCover(k-1, t+1, sr, sc);}else{Board[br][bc] = t;BoardCover(k-1, t+1,  br, bc); }}int main()
{int k; //棋盘格是2^k*2^kint sr = 0;int sc = 0;scanf("%d %d %d",&k, &sr, &sc);int t = 0;
//  printf("%d %d",sr,sc); //测试输出Board[sr][sc] = 5;BoardCover(k-1, t+1, sr, sc);for(int i = 0; i < pow(2,k); i++){for(int j = 0; j < pow(2,k); j++){printf("%d ",Board[i][j]);}printf("\n");}return 0;
}

代码

最后我选择了最左上角的点作为可变化的点其余的跟着一起变化

但是我发现数字没有办法跟着t一直相加 而是一直徘徊在123 而不到21

这个时候,我发现必须得加一个全局变量,得跟着函数的变化而变化,每递归一次函数,这个全局变量的值都得+1

#include<stdio.h>
#include<math.h>
int Board[100][100] = {0};
//必须得设置全局变量
int title = 1;
/*左上角br: 左上角bc:特殊点sr:特殊点sc:中心点tr:中心点tc: */ //解决问题 t无法一直加
void BoardCover(int size, int t, int sr, int sc, int br, int bc)
{int Lsize = size/2;int tr = br + Lsize;int tc = bc + Lsize;t = title; // printf("size %d\n",size); if(size == 1) {
//      for(int i = 0; i < pow(2,3); i++)
//  {
//      for(int j = 0; j < pow(2,3); j++)
//      {
//          printf("%d ",Board[i][j]);
//      }
//      printf("\n");
//  }
//  printf("\n");return;}//   printf("size %d\n",size);
//  printf("Lsize %d\n",Lsize);
//  printf("sr %d sc %d\n",sr, sc);
//  printf("br %d bc %d\n",br, bc);
//  printf("tr %d tc %d\n",tr, tc);
//  printf("t %d \n",t);
//  printf("title %d\n",title);
//  printf("\n");title++; if(sr <= tr-1 && sc <= tc-1){BoardCover(Lsize, t, sr, sc, br, bc);}else{Board[tr-1][tc-1] = t; BoardCover(Lsize, t, tr-1, tc-1, br, bc);}if(sr <= tr-1 && sc >= tc){BoardCover(Lsize, t, sr, sc, br, bc+Lsize);}else{Board[tr-1][tc] = t; BoardCover(Lsize, t, tr-1, tc, br, bc+Lsize);}if(sr >= tr && sc <= tc-1){BoardCover(Lsize, t, sr, sc, br+Lsize, bc);}else{Board[tr][tc-1] = t; BoardCover(Lsize, t, tr, tc-1, br+Lsize, bc);}if(sr >= tr && sc >= tc){BoardCover(Lsize, t, sr, sc, br+Lsize, bc+Lsize);}else{Board[tr][tc] = t; BoardCover(Lsize, t, tr, tc, br+Lsize, bc+Lsize);}} int main()
{int k; //棋盘格是2^k*2^kint sr = 0;int sc = 0;   scanf("%d %d %d",&k, &sr, &sc);int t = 0;int size = pow(2,k);Board[sr][sc] =   t;BoardCover(size, t, sr, sc, 0, 0);for(int i = 0; i < pow(2,k); i++){for(int j = 0; j < pow(2,k); j++){if(j == pow(2,k)-1){printf("%d",Board[i][j]);break;}printf("%-4d",Board[i][j]);}printf("\n");}return 0;
}

算法设计与分析 实验二 递归和循环相关推荐

  1. 深大算法设计与分析实验二——分治法求最近点对问题

    源代码: 深大算法设计与分析实验二--分治法求最近点对问题代码-C/C++文档类资源-CSDN下载 目录 实验问题 一.实验目的: 二.内容: 三.算法思想提示 产生不重复的随机点算法: 蛮力算法: ...

  2. 算法设计与分析 实验二 分治法求解最近点对问题

    分治法求解最近点对问题 一.实验目的与要求 1.实验基本要求 2.实验亮点 二.实验内容与方法 三.实验步骤与过程 (一)一些准备工作 1.实验流程 2.数据生成与去除重复点 (二)暴力穷举法 1.算 ...

  3. 算法设计与分析 实验二 贪心算法

    实验2.<贪心算法实验> 一.实验目的 了解贪心算法思想 掌握贪心法典型问题,如背包问题.作业调度问题等. 二.实验内容 编写一个简单的程序,实现单源最短路径问题. 编写一段程序,实现找零 ...

  4. 算法设计与分析实验二:动态规划法实现TSP问题和0/1背包问题

    [实验目的] 1.熟练掌握动态规划思想及教材中相关经典算法. 2.使用动态规划法编程,求解0/1背包问题和TSP问题. TSP问题 一.实验内容: TSP问题是指旅行家要旅行n个城市,要求每个城市经历 ...

  5. 太原理工大学linux与python编程r实验报告_太原理工大学算法设计与分析实验报告...

    <太原理工大学算法设计与分析实验报告>由会员分享,可在线阅读,更多相关<太原理工大学算法设计与分析实验报告(12页珍藏版)>请在人人文库网上搜索. 1.本科实验报告课程名称: ...

  6. 格雷码算法c语言实验报告,算法设计与分析实验报告

    本科生实验报告 课程名称:算法设计与分析 实验项目:递归和分治算法 实验地点:计算机系实验楼110 专业课:物联网1601学生.2016002105 学生姓名:于 指导员:郝晓丽 2018年5月4日 ...

  7. 算法设计与分析实验指导(完整版)

    算法设计与分析实验指导 文章目录 算法设计与分析实验指导 1. 快速排序及第k小数 1.1 快速排序 1.1.1 Implementation 1 1.1.2 算法特性分析 1.1.3 Improve ...

  8. C/C++ 算法设计与分析实验报告

    算法设计与分析实验报告 算法实验整体框架的构建 菜单代码块 选择函数代码块 主函数代码块 实验模块Ⅰ:算法分析基础--Fibonacci序列问题 实验解析 Fibonacci序列问题代码块 实验模块Ⅱ ...

  9. 计算机算法设计与分析 动态规划 实验报告,动态规划法解最长公共子序列(计算机算法设计与分析实验报告).doc...

    动态规划法解最长公共子序列(计算机算法设计与分析实验报告) 实报 告 实验名称:任课教师::姓 名:完成日期:二.主要实验内容及要求: 要求按动态规划法原理求解问题: 要求交互输入两个序列数据: 要求 ...

  10. 【图的着色问题】算法设计与分析实验1

    计算机科学与工程学院实验报告 课程名称 算法设计与分析 班级 实验内容 实验1:图的着色问题 指导教师 姓名 重剑DS 学号 实验日期 2022.04.28 一.问题描述,含输入.输出数据内容.格式 ...

最新文章

  1. oracle 分组排序 update,oracle分组排序
  2. 22.调用delay()方法延时执行动画效果
  3. SoftReference的用法
  4. Gallery 3D+倒影 滑动切换图片示例(转)
  5. python动态创建字典_如何在Python中创建动态命名字典?
  6. iOS 浅谈:深.浅拷贝与copy.strong
  7. Webrtc 开源代码的简单介绍
  8. 删除下拉框只找23火星软件_用Rhino秀个火星榨汁机?
  9. Spark RDD概念学习系列之Pair RDD的分区控制
  10. C++实现简单读取Obj格式文件
  11. 【Ydui.js】------ ydui.js 中的 util 中的方法讲解如何调用使用 例如:获取地址栏信息,js 倒计时,cookie, 获取图片地址等
  12. 梯度消失和梯度爆炸原因及其解决方案
  13. 机器学习之线性回归 Linear Regression(三)scikit-learn算法库
  14. github搜索语法-信息搜集指南----总结
  15. Rikka with Travels
  16. 一份报告引发的血案:二手车电商老大车易拍被黑的72小时
  17. 提高制作PPT效率,让这些资源来帮你
  18. .Net之时间轮算法(终极版)定时任务
  19. 股票API之----------雅虎财经频道
  20. 轻薄本外接显示器后图像不清晰的问题

热门文章

  1. 大连理工大学校内FTP列表
  2. 无广告 齐全 简洁 免费的音乐开源软件(支持 电脑max win linux 手机 )——lxMusic
  3. lammps模拟“lost atoms”原子原因及解决方法
  4. Golang:redis lua lib
  5. 北斗协议解析(北三)
  6. 婴儿抽抽乐玩具的EN71测试解析
  7. stm32获取cpu序列号
  8. 基于RedisMySQL接口幂等性设计
  9. 学生成绩预测模型_哥本哈根两学生开发新模型,预测深度学习算法碳排放量
  10. 面向对象程序课程设计-【酒店客房预订系统】