0-1规划在编程问题中的应用(UnityC#脚本/折返约瑟夫/OpenGL机器人摆臂循环)

news2024/11/15 21:27:25

一、0-1规划的定义

百度百科的解释:0-1规划是决策变量仅取值0或1的一类特殊的整数规划。在处理经济管理中某些规划问题时,若决策变量采用 0-1变量即逻辑变量,可把本来需要分别各种情况加以讨论的问题统一在一个问题中讨论。

如上面所说,0-1规划是采样0和1作为逻辑变量处理问题的方法,并且经常是用在处理经济管理中。那么为题就来了,我是怎么发现这个东西的呢?学校里压根没教过这个算法。

这还得归功于B站两位UP主M_StudioCellStudio,当然并没有直接关系,而是间接关系。

二、发现的缘由

在去年,也就是我大二上学期的时候,在B站看了M_Studio老师的2D横板闯关游戏案例教学和CellStudio老师的FPS游戏学习案例,因为当时想练一练C#编写游戏脚本,于是就学了CellStudio老师的FPS案例和M_Studio老师的小狐狸的2D横板闯关游戏案例(当然这个小狐狸系列的视频已经被下架删除了)。

当然重点都不是这些,而是在脚本中有两个防止角色二段跳的代码吸引了我。如下图

我们就算不知道Unity中的一些函数,也可以脑补出实现跳跃的方法。只要我们学过条件判断if,可以很自然的想到,if (按下空格) {角色起跳}; 这么一个逻辑伪码。但是它太简单了,以至于如果玩家一直按空格角色会一直跳,这显然不符合市面上大部分的游戏规则。

于是我们看上图这段代码,在这个横板2D闯关游戏案例里,他用了一个coll.isTouchingLayers(ground)来检测角色是否在地面上。在FPS案例里,同样有characterController.isGrounded来检测角色是否在地面上。

这样我们就可以想到,角色起跳时要同时满足两个条件,一个是玩家按下跳跃键,二是角色在地面上,至于这两个函数是怎么检测角色在地面上的咱们不说。我想说的是,角色是否在地面上这个是否,它让你想到了什么?Bool型对吗?0/1True or False。这就是我想说的,完全可以当成如果角色在地面上,那么这个isGrounded变量就是1,不在地面上就是0,这是一个很简单的逻辑,却能解决很多问题。

三、实际应用

1.折返约瑟夫问题

我并不是发现了这个方法之后马上应用的,而是在大二上学期的一次数据结构作业中,一次偶然的机会发现了这个方法的好用之处。那次作业我也发了文章,详见:[C语言、C++]数据结构作业:用双向链表和0-1变量实现折返约瑟夫问题_反约瑟夫问题


 

对,折返约瑟夫问题,我们回忆一下普通的约瑟夫问题,是约瑟夫环,用循环链表就可以解决。然后那次作业留的是修改后的折返约瑟夫问题,也就是摒弃了环的结构,而变成了线性,从一端到另一端,然后再往回遍历,循环往复,那我们自然想到双向链表,然后让指针在两头来回遍历即可,这里有一个问题,如何让程序知道,你的指针此时是应该向右遍历还是向左遍历呢?这是一个嵌套的过程,有人可能会说用递归,我没试过但感觉可以,但是很难想很费脑子。于是我们之上介绍的isGrounded变量就起作用了,只不过这里我换成了isBack,没有区别,反正都是0/1。

#include <iostream>
using namespace std;
typedef struct LinkNode {
	int data;
	LinkNode* next;
	LinkNode* pre;
}*LinkList;
void InitLinkList(LinkList& L) {
	L = NULL;
}
void CreatRear(LinkList& L,int n) {
	L = NULL;
	if (n <= 0)return;
	else {
		L = new LinkNode;
		cin >> L->data;
		L->pre = NULL; L->next = NULL;
		if (n > 1) {
			LinkNode* r = L;
			for (int i = 1; i < n; i++) {
				LinkNode* s = new LinkNode;
				cin >> s->data;
				r->next = s;
				s->pre = r;
				r = r->next;
			}
			r->next = NULL;
		}
	}
}
void Returning_Joseph(int n, int m) {
	LinkList L; InitLinkList(L);
	CreatRear(L, n);
	LinkNode* p = L; int isBack = 0;
	for (int i = 0; i < n - 1; i++) {
		int j = 0;
		while (j < m - 1) {
			if (isBack == 0) {
				while (p->next != NULL && j < m - 1) {
					p = p->next; j++;
				}
				if (p->next == NULL)isBack = 1;
			}
			if (isBack == 1) {
				while (p->pre != NULL && j < m - 1) {
					p = p->pre; j++;
				}
				if (p->pre == NULL)isBack = 0;
			}
		}
		cout << p->data << " ";
		LinkNode* r = p;
		if (p->next == NULL || p->pre == NULL) {
			if (p->next == NULL) {
				p = p->pre;
				delete(p->next);
			}
			else {
				p = p->next;
				delete(p->pre);
			}
		}
		else {
			p->pre->next = p->next;
			p->next->pre = p->pre;
			if (isBack == 0)p = p->next;
			else p = p->pre;
			r->next = NULL; r->pre = NULL;
			delete(r);
		}
	}
	cout << endl;
	cout << p->data << "是胜者"; 
}
int main(){
	Returning_Joseph(5, 3);
}

0/1的逻辑也很简单,只要发现下一个后继/前驱指针为NULL,改变isBack的值,前面写两个分支条件判断,isBack是0,向有遍历指针,isBack是1,向左遍历指针,问题就解决了。

2.OpenGL机器人走路摆臂循环

这是最近计算机图形学OpenGL的一次作业,让写一个机器人的程序,其中有一个要求,就是当按下‘w’键时,机器人会摆臂迈腿,像人一样,于是我就又想到了这个方法。

void keyboard(unsigned char key, int x, int y)
{
	switch (key) {
	case'f':
		feet1 = (feet1 + 5) % 90;//180
		feet2 = (feet2 + 5) % 90;
		glutPostRedisplay();
		break;
	case 's':
		arm2 = (arm2 + 5) % 360;
		glutPostRedisplay();
		break;
	case 'e':
		hand3 = (hand3 - 5) % 180;//180
		glutPostRedisplay();
		break;
	case 'h':
		hand2 = (hand2 - 5) % 180;
		hand4 = (hand4 - 5) % 180;
		glutPostRedisplay();
		break;
	case 'w':
		if (isnext == 0) {
			arm2 = (arm2 + 5) % 360;
			arm1 = (arm1 - 5) % 360;
			leg1 = (leg1 - 5) % 180;
			leg2 = (leg2 + 5) % 180;
			if (leg2 == 40) {
				isnext = 1;
			}
		}
		else {
			arm2 = (arm2 - 5) % 360;
			arm1 = (arm1 + 5) % 360;
			leg1 = (leg1 + 5) % 180;
			leg2 = (leg2 - 5) % 180;
			if (leg2 == -40) {
				isnext = 0;
			}
		}
		glutPostRedisplay();
		break;

	case 27:
		//exit(0);
		break;

	default:
		break;
	}
}

如上是键盘交互的代码,咱们不看那么多直接看有关w的那段,如下面:

case 'w':
		if (isnext == 0) {
			arm2 = (arm2 + 5) % 360;
			arm1 = (arm1 - 5) % 360;
			leg1 = (leg1 - 5) % 180;
			leg2 = (leg2 + 5) % 180;
			if (leg2 == 40) {
				isnext = 1;
			}
		}
		else {
			arm2 = (arm2 - 5) % 360;
			arm1 = (arm1 + 5) % 360;
			leg1 = (leg1 + 5) % 180;
			leg2 = (leg2 - 5) % 180;
			if (leg2 == -40) {
				isnext = 0;
			}
		}

通过上面的代码,大家应该知道了大致的思路,isnext就是我设的一个0/1的逻辑变量,当它为0时,左胳膊和右腿往前旋转,右胳膊和左腿往后旋转,当isnext为1的时候,再反过来就好了。改变isnext的条件也很简单,就是腿旋转达到一定角度的时候,比如左腿向前旋转到40°的时候更改,这里其实我简化了,因为胳膊和腿的旋转步长是相同的,所以判断胳膊和腿的任何一个旋转到一定角度然后更改isnext变量都可以,否则会更加复杂,但是我说的这个0/1变量的思想已经包含在其中了。

四、视频讲解

0-1规划在编程问题中的应用(UnityC#脚本/折返约瑟夫/OpenGL机器人摆臂循环)_哔哩哔哩_bilibiliicon-default.png?t=N3I4https://www.bilibili.com/video/BV1UM4y1b7pK/?spm_id_from=333.999.0.0

五、总结

总之,虽然这不是一个什么算法,但是我觉得这是解决一套问题的一种非常好用的方法,简单的说,只要你解决问题的过程中需要分情况讨论,且两种情况是相互约束的这么一种逻辑,就比如地面检测,你不可能同时在地上和空中两种状态,折返约瑟夫你不可能同时向左和右遍历,机器人走路也是,不可能同时迈两只腿或者抬起两只胳膊,这些都是一种逻辑,也就都可以用这种方法解决,虽然很简单,但是能解决很多问题,在最开始的时候我还不知道这个叫做0-1规划,我自己乱起的叫0-1变量,但是对我来说还是很有意义的,学习中的发现的快乐可能就在于此吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/510055.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

记csdn打不开或打开缓慢后的修复--如何查找dns并修改hosts文件

记csdn打开缓慢后的修复–如何查找dns并修改hosts文件 问题&#xff1a; CSDN文章打开的十分缓慢&#xff0c;经常出现无法打开页面的错误提示 &#xff08;以前用的好好的&#xff0c;现在不知道公司局域网改了什么东西&#xff0c;导致我的电脑打开CSDN经常缓慢好久&#x…

ACM - 其他算法 - 基础(前缀和 + 差分)

ACM- 其他算法 一、前缀和模板例题1、区间余数求K倍区间个数&#xff1a;AcWing 1230. K倍区间例题2、前缀和哈希求最长个数平分子串:Leetcode 面试题 17.05 字母与数字 二、差分1、一维差分2、二维差分 一、前缀和 模板 //一维前缀和 S[i] a[1] a[2] ... a[i] a[l] ... …

【行情速递】MLCC龙头涨价;车厂砍单芯片;台积电28nm设备订单全部取消!

导语&#xff1a;进入第二季度&#xff0c;MLCC龙头三环集团官宣涨价!风华高科紧随其后。车市价格战蔓延至芯片端&#xff0c;车厂开始砍单芯片&#xff0c;短短半年时间不到&#xff0c;车用芯片市场从价格飞涨和一片难求的背景&#xff0c;转为砍单与降价促销...更多详情请阅…

智能警示输出器在ESD系统中的作用

ESD&#xff08;Electrostatic Discharge&#xff09;是指静电放电&#xff0c;是一种电子元器件损坏的主要原因之一。在电子制造业中&#xff0c;ESD防静电系统是非常重要的&#xff0c;可以有效地保护电子元器件&#xff0c;避免因静电放电而造成的损坏和故障。而智能警示输出…

Spring事务(编程式事务声明式事务)

Spring中编程式事务的实现&#xff1a; 此方式包含了三个重要的操作&#xff1a;获取事务、提交事务、回滚事务。 以及依赖两个重要的对象&#xff1a;DataSourceTransactionManager、TransactionDefinition 使用编程式事务示例&#xff1a; RestController public class Use…

进程间通信都有哪些方法?

进程间通信是架构复杂系统的基石。复杂系统往往是分成各种子系统、子模块、微服务等等&#xff0c;按照 Unix 的设计哲学&#xff0c;系统的每个部分应该是稳定、独立、简单有效&#xff0c;而且强大的。系统本身各个模块就像人的器官&#xff0c;可以协同工作。而这个协同的枢…

后端常用的加密算法及hash运算

文章目录 基础知识1.加密三要素2.常用的两种加密方式⭐️3.凯撒密码 对称加密1. 编码概念2. DES — Data Encryption Standard3. 3DES — Triple-DES4. AES — Advanced Encryption Standard5. 分组密码模式6. 在golang中使用对称加密⭐️6.1 填充函数6.2 DESCBC API接口6.3 AE…

Git Clone 报错 `SSL certificate problem: unable to get local issuer certificate`

如果您在尝试克隆Git存储库时得到 “SSL certificate problem: unable to get local issuer certificate” 的错误,这意味着Git无法验证远程存储库的SSL证书。如果SSL证书是自签名的&#xff0c;或者SSL证书链有问题&#xff0c;就会发生这种情况。 $ git clone https://githu…

2021年上半年网络工程师真题详解(全套)

请点击↑关注、收藏&#xff0c;本博客免费为你获取精彩知识分享&#xff01;有惊喜哟&#xff01;&#xff01; 1、以下关于RISC和CISC计算机的叙述中&#xff0c;正确的是&#xff08; &#xff09;。 A、RISC不采用流水线技术&#xff0c;CISC采用流水线技术 B、RISC使用…

若依框架AjaxResult改造适应Swagger接口文档

概述 若依框架后端使用的响应对象AjaxResult&#xff0c;和Swagger存在不兼容问题&#xff0c;导致返回体即使使用了Swagger注解&#xff0c;但是Swagger接口文档中&#xff0c;不显示返回体的对象Swagger文档&#xff1a; [外链图片转存失败,源站可能有防盗链机制,建议将图片…

【Linux】Linux入门学习之常用命令二

介绍 这里是小编成长之路的历程&#xff0c;也是小编的学习之路。希望和各位大佬们一起成长&#xff01; 以下为小编最喜欢的两句话&#xff1a; 要有最朴素的生活和最遥远的梦想&#xff0c;即使明天天寒地冻&#xff0c;山高水远&#xff0c;路远马亡。 一个人为什么要努力&a…

Flutter学习之旅 - 路由

文章目录 Flutter路由介绍普通路由普通路由传值 命名路由将routes的配置提到外面(使用的是Map)命名路由传值 路由跳转返回上一级路由替换路由返回到根路由返回Tabs后到指定页面 Flutter路由介绍 flutter中的路由通俗就是页面跳转。在Flutter中通过Navigator(学过reactjs或小程序…

idea使用Database连接数据库报错ssm证书验证失败无法建立安全连接

项目场景&#xff1a; idea使用Database连接数据库报错ssm证书验证失败无法建立安全连接 问题描述 [08S01] 驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接。错误:“The server selected protocol version TLS10 is not accepted by client preferenc…

Java Agent

摘要 ​ JavaAgent就是Java探针&#xff0c;是一个JVM插件&#xff0c;常用于代码热更新&#xff0c;AOP&#xff0c;JVM监控等功能。这个技术对大多数的同学来说可能有点陌生&#xff0c;但是对Java软件开发人员来说肯定都多多少少接触过&#xff0c;只是相对其原理&#xff…

Selenium技术在CentOS6.8系统的腾讯云服务器上的相关使用

目录 一、解释说明二、操作过程中Linux相关命令1、下载谷歌浏览器2、查看谷歌浏览器的版本3、下载对应版本的谷歌驱动&#xff08;或者本地上传&#xff09;4、解压下载的文件5、移动下载文件6、给予文件执行权限7、更新pip3到最高版本8、下载Selenium第三方库9、正式测试10、最…

C#学习笔记--由浅至深理解IEnumerable和IEnumerator

目录 前言总结 IEnumerable 和 IEnumeratorIEnumerable是什么&#xff1f;IEnumerator是什么&#xff1f;总结 结尾预告 前言 上篇文章我是自己实现了一个容器C#学习笔记–实现一个可以重复权重并且能够自动排序的容器–MultiplySortedSet 写完之后突然想到一个问题&#xff…

PMP课堂模拟题目及解析(第6期)

51. 管理层将一个国际项目分配给一位新项目经理。这是该项目经理第一次与团队合作&#xff0c;团队成员位于两个国家&#xff0c;数量平均分布&#xff0c;一个团队由最合适作为个人工作的成员组成&#xff0c;另一个团队由最适合作为团队工作的成员组成。项目经理该怎么做&am…

抖音商城小程序搭建的注意事项

抖音商城小程序已经成为了越来越多电商企业的选择&#xff0c;毕竟它具有强大的用户资源和社交传播力。但是&#xff0c;在搭建抖音商城小程序的过程中&#xff0c;还有一些需要注意的事项。 1、制定明确的策略和目标 在搭建抖音商城小程序前&#xff0c;必须事先制定明确的策…

65.网站个性框架

之前介绍过集中个性网站 严肃优雅型极简主义普通/中性大胆/自信平静祥和创业/上进俏皮/好玩 严肃优雅型 概述 奢华和优雅的设计&#xff0c;基于细小的衬线字体、金色或粉色的颜色和高质量的大图片。 行业 房地产、高端时尚、饰品类&#xff0c;奢侈产品或服务 排版 有衬…

(构造函数的补充2)类型转换与临时变量(新对象)的生成与explicit关键字,类的静态成员变量与成员函数及其应用

(构造函数的补充2)类型转换与临时变量(新对象)的生成与explicit关键字 如果说一个构造函数是单个参数&#xff0c;或者说有多个参数但是第一个参数没有默认值&#xff0c;而其余均有默认值&#xff0c;这时候就特别需要注意类型转换的问题。首先必须得知道的一点就是说一旦有类…