UVA-11212 编辑书稿 题解答案代码 算法竞赛入门经典第二版

2023-11-17

GitHub - jzplp/aoapc-UVA-Answer: 算法竞赛入门经典 例题和习题答案 刘汝佳 第二版

这道题目在书上的“迭代加深搜索”章节出现,即是采用迭代加深搜索的方法来做。

但是咋一看题目,我认为用广度优先搜索也合适。因为题目要求是找到最短的粘贴次数,使用程序遍历一层一层搜搜正合适。而且数据量也不算太大, 队列和是否访问过的flag都可以存下。

如果使用迭代加深搜索,搜到第n+1次时,会对前n次的计算结果进行重复搜索,效率不高。但是层序遍历则没这个问题。

有些同学会说迭代加深搜索可以剪枝,可以有启发函数。那么广度优先搜索也可以剪枝,也可以有启发函数,而且是一样的启发函数。因此这不是问题。

由于需要练习“迭代加深搜索”,因此我还是用这个方法做的,感兴趣的同学可以试一下广度优先搜索是否合适。

我尝试使用了flag记录使用访问过的标志,但是发现这样效率更低。如果剪枝合适,不记录也是可以的。

使用flag记录: 7270ms

不使用flag记录: 1400ms

数据粘贴的还原的方法我做的比较繁琐,但是比较容易理解,这个还可以优化。

使用flag记录的代码(更慢)

#include<stdio.h>
#include<string.h>

int n;
int origin[10];
int arrnow[10];
int arrtemp[10];
char findMap[1000000000];

void printArr(int * arr) {
	for(int i = 0; i < n; ++i) {
		printf("%d ", arr[i]);
	}
	printf("\n");
} 

// 是否访问过

bool isFind(int * arr, int step) {
	int num = 0;
	for(int i = 0; i < n; ++i) {
		num = num * 10 + arr[i]-1;
	}
	if(!findMap[num]) return false;
	return findMap[num] < step;
}

// 设置访问 
void findFlag(int * arr, int step) {
	int num = 0;
	for(int i = 0; i < n; ++i) {
		num = num * 10 + arr[i]-1; 
	}
	findMap[num] = step; 
}

// 获取数组中后继不正确的数字个数 
int getErrorNum(int * arr) {
	int num = 0;
	for(int i = 1; i < n; ++i) {
		if(arr[i] != arr[i-1]+1) ++num;
	}
	return num;
} 

// 当前最少需要的移动次数 
int getMinTime(int * arr) {
	int num = getErrorNum(arr);
	if(num % 3) return num / 3 + 1;
	return num / 3;
}

// 移动位置 
void movePos(int start, int end, int pos) {
	memcpy(arrtemp, arrnow, sizeof(arrnow));
	int movelen = end-start + 1;
	int i, j, k;
	if(start > pos) {
		for(i = 0; i < movelen; ++i)
		arrnow[pos + i] = arrtemp[start + i];
		for(i = 0; i < pos; ++i)
			arrnow[i] = arrtemp[i];
		for(i = pos; i < start; ++i)
			arrnow[i + movelen] = arrtemp[i];
		for(i = end+1; i < n; ++i)
			arrnow[i] = arrtemp[i];
	}
	if(end < pos) {
		for(i = 0; i < movelen; ++i)
			arrnow[pos + i - movelen] = arrtemp[start + i];
		for(i = 0; i < start; ++i)
			arrnow[i] = arrtemp[i];
		for(i = end+1; i < pos; ++i)
			arrnow[i-movelen] = arrtemp[i];
		for(i = pos; i < n; ++i)
			arrnow[i] = arrtemp[i];
	}
}

// 恢复之前移动的位置 
void restorePos(int start, int end, int pos) {
	int movelen = end-start + 1;
	if(start > pos)
		movePos(pos, pos + movelen - 1, start + movelen);
	if(end < pos)
		movePos(pos - movelen, pos-1, start);
}

// 每一轮迭代
bool handleTime(int num, int len) {
	// printf("%d %d\n",num, getErrorNum(arrnow));
	// 到达终点 
	if(num == len) {
		if(!getErrorNum(arrnow)) return true;
		return false;
	}
	// 继续迭代 
	int i, j, k, numnow;
	for(int i = 0; i < n; ++i) {
		if(i != 0 && arrnow[i-1] == arrnow[i]-1) continue;
		for(j = i; j < n; ++j) {
			if(j != n-1 && arrnow[j+1] == arrnow[j]+1) continue;
			for(k = 0; k <= n; ++k) {
				if(k >= i-1 && k <= j+1) continue;
				// printf("-------\n");
				// printArr(arrnow);
				// 移动
				movePos(i, j, k);
				numnow = num + 1;
				// printf("%d %d %d\n", i, j, k);
				// printArr(arrnow);
				// 剪枝
				if((getMinTime(arrnow) <= (len - numnow)) && !isFind(arrnow, numnow)) {
				// if(getMinTime(arrnow) <= (len - num)) {
					findFlag(arrnow, numnow);
					// 递归
					if(handleTime(numnow, len)) return true;
				}
				// 恢复
				restorePos(i, j, k);
				// printArr(arrnow);
			}
		}
	}
	return false;
}

// 处理入口 
int handle() {
	int i, j;
	for(i = getMinTime(origin); i < 8; ++i) {
		memcpy(arrnow, origin, sizeof(arrnow));
		memset(findMap, 0, sizeof(findMap));
		// 每一轮加深迭代
		if(handleTime(0, i)) return i;
	}
	return 8; 
}

int main() {
	int t = 0;
	int i, j;
	while(scanf("%d\n", &n) == 1 && n > 0) {
		++t;
		for(i = 0; i < n; ++i)
			scanf("%d", &origin[i]);
		j = handle();
		printf("Case %d: %d\n", t, j);
	}
	return 0;	
}

不使用flag记录的代码

#include<stdio.h>
#include<string.h>

int n;
int origin[10];
int arrnow[10];
int arrtemp[10];

void printArr(int * arr) {
	for(int i = 0; i < n; ++i) {
		printf("%d ", arr[i]);
	}
	printf("\n");
} 

// 获取数组中后继不正确的数字个数 
int getErrorNum(int * arr) {
	int num = 0;
	for(int i = 1; i < n; ++i) {
		if(arr[i] != arr[i-1]+1) ++num;
	}
	return num;
} 

// 当前最少需要的移动次数 
int getMinTime(int * arr) {
	int num = getErrorNum(arr);
	if(num % 3) return num / 3 + 1;
	return num / 3;
}

// 移动位置 
void movePos(int start, int end, int pos) {
	memcpy(arrtemp, arrnow, sizeof(arrnow));
	int movelen = end-start + 1;
	int i, j, k;
	if(start > pos) {
		for(i = 0; i < movelen; ++i)
		arrnow[pos + i] = arrtemp[start + i];
		for(i = 0; i < pos; ++i)
			arrnow[i] = arrtemp[i];
		for(i = pos; i < start; ++i)
			arrnow[i + movelen] = arrtemp[i];
		for(i = end+1; i < n; ++i)
			arrnow[i] = arrtemp[i];
	}
	if(end < pos) {
		for(i = 0; i < movelen; ++i)
			arrnow[pos + i - movelen] = arrtemp[start + i];
		for(i = 0; i < start; ++i)
			arrnow[i] = arrtemp[i];
		for(i = end+1; i < pos; ++i)
			arrnow[i-movelen] = arrtemp[i];
		for(i = pos; i < n; ++i)
			arrnow[i] = arrtemp[i];
	}
}

// 恢复之前移动的位置 
void restorePos(int start, int end, int pos) {
	int movelen = end-start + 1;
	if(start > pos)
		movePos(pos, pos + movelen - 1, start + movelen);
	if(end < pos)
		movePos(pos - movelen, pos-1, start);
}

// 每一轮迭代
bool handleTime(int num, int len) {
	// 到达终点 
	if(num == len) {
		if(!getErrorNum(arrnow)) return true;
		return false;
	}
	// 继续迭代 
	int i, j, k, numnow;
	for(int i = 0; i < n; ++i) {
		if(i != 0 && arrnow[i-1] == arrnow[i]-1) continue;
		for(j = i; j < n; ++j) {
			if(j != n-1 && arrnow[j+1] == arrnow[j]+1) continue;
			for(k = 0; k <= n; ++k) {
				if(k >= i-1 && k <= j+1) continue;
				// 移动
				movePos(i, j, k);
				numnow = num + 1;
				// 剪枝
				if((getMinTime(arrnow) <= (len - numnow))) {
					// 递归
					if(handleTime(numnow, len)) return true;
				}
				// 恢复
				restorePos(i, j, k);
			}
		}
	}
	return false;
}

// 处理入口 
int handle() {
	int i, j;
	for(i = getMinTime(origin); i < 8; ++i) {
		memcpy(arrnow, origin, sizeof(arrnow));
		// 每一轮加深迭代
		if(handleTime(0, i)) return i;
	}
	return 8; 
}

int main() {
	int t = 0;
	int i, j;
	while(scanf("%d\n", &n) == 1 && n > 0) {
		++t;
		for(i = 0; i < n; ++i)
			scanf("%d", &origin[i]);
		j = handle();
		printf("Case %d: %d\n", t, j);
	}
	return 0;	
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

UVA-11212 编辑书稿 题解答案代码 算法竞赛入门经典第二版 的相关文章

随机推荐

  • 【数据结构课设】 浮点数计算器

    一 简介 1 功能介绍 实数的计算 支持取对数 幂次 开方及加减乘除运算 2 模块设计 1 菜单界面 2 计算器功能简介 3 计算器功能实现 3 计算器功能实现方法 1 字符串读入用户的表达式 2 处理字符串 包括提取实数以及中缀转后缀 维
  • idea开发中git合并的代码,

    方法一 将master主分支 合并到 子分支dev上 1 当前如果在dev分支上 先提交dev分支的代码到本地 然后推送到服务器 2 然后切换分支到master主分支上 先更新master主分支的代码到本地 然后主分支就是最新代码了 3 再
  • python 安卓模拟点击_Android后台模拟点击探索(附源码)

    工作中我们需要自制一套工具 其中遇到需要模拟点击事件的需求 类似按键精灵的功能 支持后台持续运行 满足触发条件时完成点击 经过一番探索 一共整理出两种不同的方案 AccessibilityService 和 adb shell命令 读者可自
  • Matlab中的c2d函数离散化

    把传递函数离散化 dsys c2d sys ts method 传函离散 num den tfdata dsys v 离散后提取分子分母 这里面的method有好多种 zoh 零阶保持 假设控制输入在采样周期内为常值 为默认值 foh 一阶
  • 【自动化测试】——robotframework实战(一)搭建环境

    一 前提准备 python 3 9 6 pip 下载 最新版本 setuptools 下载 最新版本 二 下载robotframework框架 管理员模式打开cmd 下载RF pip install robotframework 3 1 下
  • tomcat 配置域名

    Tomcat 配置域名 在windows中 首先找到conf下面的server xml 把Connector 标签中的端口改成80 然后把添加一个Host name为域名appBase为路径 如下 Engine 标签也是 最后在C盘 win
  • Android网络请求库的使用(okhttp、retrofit、rxjava)

    Android网络请求库的使用 前置工作 okhttp的基本使用 okhttp第一个demo okhttp的异步写法 更常见 GET请求中使用okhttp拼接参数 okhttp发起POST请求 拦截器第一个demo 打印请求的时间 retr
  • java并发编程实战

    Volatile变量 valatile是java提供的一种稍弱的同步机制 用来确保将变量的更新操作通知到其他线程 当把变量声明为volatile后 编译器与运行时都会注意到这个变量是共享的 因此不会将变量上的操作与其他内存操作一起重排序 1
  • 评测 AlibabaCloud 阿里云国际版 香港轻量云服务器的性能和网络怎么样

    此次站长带来的是 AlibabaCloud 阿里云国际版 香港轻量云服务器的评测 配置为512M内存 1核 20G云硬盘 官方网站 https www alibabacloud com 国际版 https www aliyun com 国内
  • AST混淆 二进制/八进制/十六进制数值及十六进制字符串,Unicode字符串还原

    二进制 八进制 十六进制数值及十六进制字符串 Unicode字符串还原插件 const simplifyLiteral NumericLiteral node if node extra 0 obx i test node extra ra
  • uniapp解决rich-text 富文本图片过大超出问题

    问题 如图所示 图片过大超出会超出手机屏幕 解决办法
  • 第十一届蓝桥杯 ——七段码

    题目描述 小蓝要用七段码数码管来表示一种特殊的文字 上图给出了七段码数码管的一个图示 数码管中一共有 7 段可以发光的二极管 分别标记为 a b c d e f g 小蓝要选择一部分二极管 至少要有一个 发光来表达字符 在设计字符的表达时
  • python seaborn 散点图矩阵_python数据可视化之seaborn

    seaborn importmatplotlib as mplimportmatplotlib pyplot as pltimportnumpy as npimportpandas as pd 解决坐标轴刻度负号乱码 plt rcParam
  • iOS开发问题之:Xcode打包失败IPA processing failed

    打包发现失败了 提示IPA processing failed 查看日志 IDEDistribution standard log image png 发现是因为项目中使用的SDK支持i386 x86 86这个架构 猜测是iOS13强制不支
  • 代码检视/代码审查/Code Review

    目录 一 代码检视的目的 二 代码检视前的准备 三 代码检视九句箴言 四 代码检视checklist 经验检查项 五 代码检视结果度量 六 代码质量衡量指标 七 高质量代码 一 代码检视的目的 代码检视是一种用来确认方案设计和代码实现的质量
  • Kotlin之高阶函数

    一 定义高阶函数 高阶函数和Lambda的关系密不可分 在Lambda编程的基础知识 使用的一些与集合相关的函数式API用法 如map filter函数等 又比如Kotlin的标准函数 如run apply函数等 这几个函数都有一个共同的特
  • 用python进行FamaMacBeth回归

    from linearmodels import FamaMacBeth import pandas as pd import numpy as np 生成所用面板数据集 该数据集在不同的日期有不同的个体 期望回归模型 Y 3 6 X1 4
  • 前端例程20221227:下雪动画

    演示 动图太大了不好上传 这里就放个静态图吧 实际上这里是雪花从上到下飘落的效果 代码
  • 分集 复用 多址

    1 分集 是在多条独立路径上传输相同的数据 接收端通过分集合并技术 抵抗信道衰落 提高传输可靠性 降低误码率 复用 是在多条独立路径上传输不同数据 充分利用系统资源 提高系统容量 即总数据率 2 分集 是一个信号通过多条路径送达接收端 好处
  • UVA-11212 编辑书稿 题解答案代码 算法竞赛入门经典第二版

    GitHub jzplp aoapc UVA Answer 算法竞赛入门经典 例题和习题答案 刘汝佳 第二版 这道题目在书上的 迭代加深搜索 章节出现 即是采用迭代加深搜索的方法来做 但是咋一看题目 我认为用广度优先搜索也合适 因为题目要求