Cocos2dx c++到安卓Java/kt实现Rsa、Aes、Base64加密解密

2024-01-04 10:30

本文主要是介绍Cocos2dx c++到安卓Java/kt实现Rsa、Aes、Base64加密解密,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1977年,三位数学家Rivest、Shamir 和 Adleman 设计了一种算法,可以实现非对称加密。这种算法用他们三个人的名字命名,叫做RSA算法。从那时直到现在,RSA算法一直是最广为使用的"非对称加密算法"。毫不夸张地说,只要有计算机网络的地方,就有RSA算法。这种算法非常可靠,密钥越长,它就越难破解。根据已经披露的文献,目前被破解的最长RSA密钥是232个十进制位,也就是768个二进制位,因此可以认为,1024位的RSA密钥基本安全,2048位的密钥极其安全,当然量子计算机除外。

以下下方法实现了非对称加密算法Rsa c++的加解密和java的加解密,可以在jni过程中提高安全性,代码中的公钥和私钥建议从文件获取,不以明文的方式放在本地,方法不予赘述

//
//  RsaUtil.cpp
//
//  C++加密和解密过程
//
//  Created by Versprechen on 2023/9/14.
//#include <iostream>
#include "RsaUtil.hpp"#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
#include "openssl/rsa.h"
#include "openssl/pem.h"
#include "openssl/err.h"
#include "openssl/evp.h"
#endif#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "JniTools.h"
#include "Base64Util.hpp"RsaUtil::RsaUtil()
{
}RsaUtil::~RsaUtil()
{
}
RsaUtil *RsaUtil::m_instance = nullptr;
RsaUtil *RsaUtil::getInstance()
{if (nullptr == m_instance){m_instance = new RsaUtil;}return m_instance;
}void RsaUtil::release()
{if (m_instance){}CC_SAFE_DELETE(m_instance);
}void RsaUtil::initKey()
{m_privateKey = Base64Util::getInstance()->base64_decode(m_privateKey);m_publicKey = Base64Util::getInstance()->base64_decode(m_publicKey);
}/**  非对称加密算法Rsa工具类的使用:*  双方加密解密遵循 PKCS#8 公钥和私钥格式*  1、createKey:创建公钥和私钥*     加密前需要保证公钥格式以"-----BEGIN RSA PUBLIC KEY-----"开头,以"-----END RSA PUBLIC KEY-----"结尾*     私钥以"-----BEGIN RSA PRIVATE KEY-----"开头*  2、RSAEncrypt加密,加密之后会使用base64_encode加密,防止传输错误*  3、RSADecrypt解密,解密流程是先把传回来的字符串base64_decode解密,再走加密算法**  注意:使用Jni交互的数据需要先使用base64加密/解密*/// 创建rsa的私钥和公钥,覆盖成员变量
void RsaUtil::createKeys()
{
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROIDRSA *rsa = RSA_new();BIGNUM *e = BN_new();BN_set_word(e, RSA_F4);RSA_generate_key_ex(rsa, 2048, e, NULL);BIO *publicBIO = BIO_new(BIO_s_mem());PEM_write_bio_RSA_PUBKEY(publicBIO, rsa);BIO *privateBIO = BIO_new(BIO_s_mem());EVP_PKEY *pkey = EVP_PKEY_new();EVP_PKEY_assign_RSA(pkey, rsa); // rsa will be freed when pkey is freedPEM_write_bio_PKCS8PrivateKey(privateBIO, pkey, NULL, NULL, 0, NULL, NULL);char *publicKey;long publicKeyLength = BIO_get_mem_data(publicBIO, &publicKey);char *privateKey;long privateKeyLength = BIO_get_mem_data(privateBIO, &privateKey);m_publicKey = std::string(publicKey, publicKeyLength);m_privateKey = std::string(privateKey, privateKeyLength);m_publicKey = removeKeyHeaderAndFooter(m_publicKey);m_privateKey = removeKeyHeaderAndFooter(m_privateKey);NXLOG("公钥:%s", m_publicKey.c_str());NXLOG("私钥:%s", m_privateKey.c_str());BN_free(e);BIO_free(publicBIO);BIO_free(privateBIO);EVP_PKEY_free(pkey);
#endif
}// 由于java需要去掉头尾标记符,生成之后需要去掉给他们
std::string RsaUtil::removeKeyHeaderAndFooter(const std::string &key)
{std::string result = key;std::string header1 = "-----BEGIN RSA PUBLIC KEY-----";std::string header2 = "-----BEGIN RSA PRIVATE KEY-----";std::string footer = "-----END RSA PUBLIC KEY-----";size_t pos;while ((pos = result.find(header1)) != std::string::npos)result.erase(pos, header1.length());while ((pos = result.find(header2)) != std::string::npos)result.erase(pos, header2.length());while ((pos = result.find(footer)) != std::string::npos)result.erase(pos, footer.length());return result;
}// 加密函数
std::string RsaUtil::RSAEncrypt(std::string plainText)
{
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROIDBIO *keybio = BIO_new_mem_buf(m_publicKey.c_str(), -1);RSA *rsa = PEM_read_bio_RSA_PUBKEY(keybio, NULL, NULL, NULL); // 修改这里std::string encryptedData(RSA_size(rsa), '\0');int encryptedDataLength = RSA_public_encrypt(plainText.size(), reinterpret_cast<const unsigned char *>(plainText.c_str()), reinterpret_cast<unsigned char *>(&encryptedData[0]), rsa, RSA_PKCS1_PADDING);BIO_free(keybio);RSA_free(rsa);auto output = encryptedData.substr(0, encryptedDataLength);return Base64Util::getInstance()->base64_encode(reinterpret_cast<const unsigned char *>(output.c_str()), output.length());
#endif
}// 解密
std::string RsaUtil::RSADecrypt(std::string cipherText)
{
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROIDstring decode = Base64Util::getInstance()->base64_decode(cipherText);BIO *keybio = BIO_new_mem_buf(m_privateKey.c_str(), -1);RSA *rsa = PEM_read_bio_RSAPrivateKey(keybio, NULL, NULL, NULL);std::string data(RSA_size(rsa), '\0');int dataLength = RSA_private_decrypt(decode.size(), reinterpret_cast<const unsigned char *>(decode.c_str()), reinterpret_cast<unsigned char *>(&data[0]), rsa, RSA_PKCS1_PADDING);BIO_free(keybio);RSA_free(rsa);return data.substr(0, dataLength);
#endif
}

​​​​​​​//
//  RsaUtil.hpp
//
//  Created by Versprechen on 2023/9/14.
//#ifndef RsaUtil_hpp
#define RsaUtil_hpp#include "cocos2d.h"
#include "GameState.h"
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
#include "openssl/rsa.h"
#include "openssl/pem.h"
#include "openssl/err.h"
#include "openssl/evp.h"
#endif
USING_NS_CC;class RsaUtil {
public:RsaUtil();~RsaUtil();static RsaUtil *getInstance();public:static RsaUtil *m_instance;static void release();void createKeys();std::string removeKeyHeaderAndFooter(const std::string &key);std::string RSAEncrypt(std::string plainText);std::string RSADecrypt(std::string cipherText);void initKey();//使用Rsa加密解密的公钥和私钥std::string m_privateKey = "你经过Base64之后的公钥";std::string m_publicKey = "你经过Base64之后的私钥";
};
#endif /* RsaUtil_hpp */

=====java/kt版本加解密====

package org.cocos2dx.cpp.adFrameimport java.security.KeyFactory
import java.security.KeyPair
import java.security.KeyPairGenerator
import java.security.NoSuchAlgorithmException
import java.security.interfaces.RSAPrivateKey
import java.security.interfaces.RSAPublicKey
import java.security.spec.PKCS8EncodedKeySpec
import java.security.spec.X509EncodedKeySpec
import javax.crypto.Cipherobject RSAUtils {private const val TRANSFORMATION = "RSA/ECB/PKCS1Padding"/** 生成密钥对,即公钥和私钥。key长度是512-2048,一般为1024 本文使用2048长度的key */@Throws(NoSuchAlgorithmException::class)fun generateRSAKeyPair(keyLength: Int): KeyPair? {val kpg = KeyPairGenerator.getInstance("RSA")kpg.initialize(keyLength)return kpg.genKeyPair()}/** 获取公钥 */fun getPublicKey(keyPair: KeyPair): ByteArray? {val rsaPublicKey = keyPair.public as RSAPublicKeyreturn rsaPublicKey.encoded}/** 获取私钥 */fun getPrivateKey(keyPair: KeyPair): ByteArray? {val rsaPrivateKey = keyPair.private as RSAPrivateKeyreturn rsaPrivateKey.encoded}/*** 使用公钥加密* @param content 需要加密的密文(String类型)* @param publicKeyString 公钥(String类型)* @return base64数据* @throws Exception*/@Throws(Exception::class)fun encryptByPublicKey(content: String): String? {val publicKeyString = "你经过base64之后的公钥建议从文件获取";val publicKey: ByteArray = Base64Utils.decode2byte(publicKeyString.replace("\n", "").toByteArray())// 得到公钥对象val keySpec = X509EncodedKeySpec(publicKey)val keyFactory = KeyFactory.getInstance("RSA")val pubKey = keyFactory.generatePublic(keySpec)// 加密数据val cp = Cipher.getInstance(TRANSFORMATION)cp.init(Cipher.ENCRYPT_MODE, pubKey)val byteArray = cp.doFinal(content.toByteArray())return if (byteArray != null) Base64Utils.encode2Str(byteArray) else null}/*** 使用私钥解密* @param content content 需要加密的密文* @param privateKeyString  私钥* @return String数据所以需要fastjson转object* @throws Exception*/@Throws(java.lang.Exception::class)fun decryptByPrivateKey(content: String?): String? {val privateKeyString = "你经过base64之后的私钥建议从文件获取";val privateKey = Base64Utils.decode2byte(privateKeyString.toByteArray())val encrypt: ByteArray = Base64Utils.decode2byte(content)// 得到私钥对象val keySpec = PKCS8EncodedKeySpec(privateKey)val kf = KeyFactory.getInstance("RSA")val keyPrivate = kf.generatePrivate(keySpec)// 解密数据val cp = Cipher.getInstance(TRANSFORMATION)cp.init(Cipher.DECRYPT_MODE, keyPrivate)val byteArray = cp.doFinal(encrypt)return if (byteArray != null) String(byteArray) else null}
}

=====================================================================

AES的全称是Advanced Encryption Standard,意思是高级加密标准。它的出现主要是为了取代DES加密算法的,因为我们都知道DES算法的密钥长度是56Bit,因此算法的理论安全强度是2的56次方。但二十世纪中后期正是计算机飞速发展的阶段,元器件制造工艺的进步使得计算机的处理能力越来越强,虽然出现了3DES的加密方法,但由于它的加密时间是DES算法的3倍多,64Bit的分组大小相对较小,所以还是不能满足人们对安全性的要求。于是1997年1月2号,美国国家标准技术研究所宣布希望征集高级加密标准,用以取代DES。AES也得到了全世界很多密码工作者的响应,先后有很多人提交了自己设计的算法。最终有5个候选算法进入最后一轮:Rijndael,Serpent,Twofish,RC6和MARS。最终经过安全性分析、软硬件性能评估等严格的步骤,Rijndael算法获胜。

下面是对应的对称的Aes加密算法,流程较为简单,但是加密解密效率较高

#include "AesUtil.hpp"
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
#include "openssl/aes.h"
#include "openssl/rsa.h"
#include "openssl/pem.h"
#include "openssl/err.h"
#include "openssl/evp.h"
#include "Base64Util.hpp"
#endif#define AES_KEY_LENGTH 16  // aes-128AesUtil::AesUtil()
{
}AesUtil::~AesUtil()
{
}
AesUtil *AesUtil::m_instance = nullptr;
AesUtil *AesUtil::getInstance()
{if (nullptr == m_instance){m_instance = new AesUtil;}return m_instance;
}void AesUtil::release()
{if (m_instance){}CC_SAFE_DELETE(m_instance);
}void AesUtil::printhexDump(const char *buffer, size_t len)
{if (buffer == NULL || len <= 0){return;}CCLOG("0x%x: (len=%d)[", buffer, len);for (size_t i = 0; i < len; i++){CCLOG("%.2X ", (unsigned char)buffer[i]);}CCLOG("]\n");
}
string AesUtil::aes_decrypt(string encData)
{
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROIDstring decode = Base64Util::getInstance()->base64_decode(encData);string code = FileUtils::getInstance()->getStringFromFile("com.gamezone.adventurequest.amr");if (code.length() != 16) {// Handle error: code string length is not 32}unsigned char key[17];memcpy(key, code.c_str(), 16);key[16] = '\0';unsigned char decData[1024];int decLen = 0;int outlen = 0;EVP_CIPHER_CTX *ctx2;ctx2 = EVP_CIPHER_CTX_new();EVP_CipherInit_ex(ctx2, EVP_aes_128_ecb(), NULL, key, NULL, AES_DECRYPT);EVP_CipherUpdate(ctx2, decData, &outlen, (const unsigned char*)(decode.c_str()), decode.length());decLen = outlen;if(EVP_CipherFinal_ex(ctx2, decData + outlen, &outlen)){decLen += outlen;}EVP_CIPHER_CTX_free(ctx2);decData[decLen] = '\0';CCLOG("decrypt: %s\n", decData);return StringUtils::format("%s",decData);
#endif
}string AesUtil::aes_encrypt(string rawData)
{
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROIDstring code = FileUtils::getInstance()->getStringFromFile("");//获取你的秘钥if (code.length() != 16) {// Handle error: code string length is not 32}unsigned char key[17];memcpy(key, code.c_str(), 16);key[16] = '\0';int rawDataLen = strlen(rawData.c_str());unsigned char encData[1024];int encLen = 0;int outLen = 0;EVP_CIPHER_CTX *ctx;ctx = EVP_CIPHER_CTX_new();EVP_CipherInit_ex(ctx, EVP_aes_128_ecb(), NULL, key, NULL, AES_ENCRYPT);EVP_CipherUpdate(ctx, encData, &outLen, (const unsigned char*)(rawData.c_str()), rawDataLen);encLen = outLen;if(EVP_CipherFinal_ex(ctx, encData + outLen, &outLen)){encLen += outLen;}EVP_CIPHER_CTX_free(ctx);printhexDump(reinterpret_cast<const char *>(encData), encLen);return Base64Util::getInstance()->base64_encode(encData,encLen);
#endif
}
//
//  AesUtil.hpp
//
//  Created by Versprechen on 2023/9/19.
//#ifndef AesUtil_hpp
#define AesUtil_hpp#include <stdio.h>
#include <string>
#include "cocos2d.h"using namespace std;
using namespace cocos2d;class AesUtil {
public:AesUtil();~AesUtil();static AesUtil *getInstance();public:static AesUtil *m_instance;static void release();string aes_decrypt(string encData);string aes_encrypt(string rawData);void printhexDump(const char *buffer, size_t len);};
#endif /* AesUtil_hpp */

=====java/kt版本加解密====

package org.cocos2dx.cpp.adFrameimport android.content.Context
import java.io.BufferedReader
import java.io.InputStreamReader
import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpecobject AESUtils {lateinit var aesKey: Stringfun initAesKey(context: Context) {val stringBuilder = StringBuilder()try {val assetManager = context.assetsval bufferedReader = BufferedReader(InputStreamReader(//获取你的秘钥))var line: String?while (bufferedReader.readLine().also { line = it } != null) {stringBuilder.append(line)}} catch (e: Exception) {e.printStackTrace()}aesKey = stringBuilder.toString()}fun aseDecrypt(str: String): String {val key = SecretKeySpec(aesKey.toByteArray(), "AES")val cipher = Cipher.getInstance("AES/ECB/PKCS5Padding")cipher.init(Cipher.DECRYPT_MODE, key)return String(cipher.doFinal(Base64Utils.decode2byte(str.toByteArray())))}fun aesEncrypt(str: String): String {val key = SecretKeySpec(aesKey.toByteArray(), "AES")val cipher = Cipher.getInstance("AES/ECB/PKCS5Padding")cipher.init(Cipher.ENCRYPT_MODE, key)return Base64Utils.encode2Str(cipher.doFinal(str.toByteArray()))}
}

AES加密算法正常自己c++加密解密可以统一方法,但是和java、js互相加解密需要遵循以下原则,否则会解密失败,以下截图来自csdn:CryptoJS C/C++ openssl Java AES_256_ecb 加密解密互通_java aes-256-ecb 加密-CSDN博客 

在加密过程中,输出的可能是十六进制,通常先做base64再传输,以下是c++版本的Base64算法

//
//  Base64Util.cpp
//  game-blockpuzzle-mobile
//
//  Created by Versprechen on 2023/9/19.
//#include "Base64Util.hpp"
Base64Util::Base64Util()
{
}Base64Util::~Base64Util()
{
}
Base64Util *Base64Util::m_instance = nullptr;
Base64Util *Base64Util::getInstance()
{if (nullptr == m_instance){m_instance = new Base64Util;}return m_instance;
}void Base64Util::release()
{if (m_instance){}CC_SAFE_DELETE(m_instance);
}
static const std::string base64_chars ="ABCDEFGHIJKLMNOPQRSTUVWXYZ""abcdefghijklmnopqrstuvwxyz""0123456789+/";
std::string Base64Util::base64_encode(unsigned char const *bytes_to_encode, unsigned int in_len)
{std::string ret;int i = 0;int j = 0;unsigned char char_array_3[3];unsigned char char_array_4[4];while (in_len--){char_array_3[i++] = *(bytes_to_encode++);if (i == 3){char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);char_array_4[3] = char_array_3[2] & 0x3f;for (i = 0; (i < 4); i++)ret += base64_chars[char_array_4[i]];i = 0;}}if (i){for (j = i; j < 3; j++)char_array_3[j] = '\0';char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);char_array_4[3] = char_array_3[2] & 0x3f;for (j = 0; (j < i + 1); j++)ret += base64_chars[char_array_4[j]];while ((i++ < 3))ret += '=';}return ret;
}std::string Base64Util::base64_decode(std::string const &encoded_string)
{int in_len = encoded_string.size();int i = 0;int j = 0;int in_ = 0;unsigned char char_array_4[4], char_array_3[3];std::string ret;while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])){char_array_4[i++] = encoded_string[in_];in_++;if (i == 4){for (i = 0; i < 4; i++)char_array_4[i] = base64_chars.find(char_array_4[i]);char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];for (i = 0; (i < 3); i++)ret += char_array_3[i];i = 0;}}if (i){for (j = i; j < 4; j++)char_array_4[j] = 0;for (j = 0; j < 4; j++)char_array_4[j] = base64_chars.find(char_array_4[j]);char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];for (j = 0; (j < i - 1); j++)ret += char_array_3[j];}return ret;
}inline bool Base64Util::is_base64(unsigned char c)
{return (isalnum(c) || (c == '+') || (c == '/'));
}
//
//  Base64Util.hpp
//  game-blockpuzzle-mobile
//
//  Created by Versprechen on 2023/9/19.
//#ifndef Base64Util_hpp
#define Base64Util_hpp#include <stdio.h>
#include <string>
#include "cocos2d.h"using namespace std;class Base64Util {
public:Base64Util();~Base64Util();static Base64Util *getInstance();public:static Base64Util *m_instance;static void release();std::string base64_encode(unsigned char const *bytes_to_encode, unsigned int in_len);std::string base64_decode(std::string const &encoded_string);inline bool is_base64(unsigned char c);};
#endif /* Base64Util_hpp */

这篇关于Cocos2dx c++到安卓Java/kt实现Rsa、Aes、Base64加密解密的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/569032

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<