C#,动态规划的集合划分问题(DP Partition problem)算法与源代码

动态规划问题中的划分问题

动态规划问题中的划分问题是确定一个给定的集是否可以划分为两个子集,使得两个子集中的元素之和相同。

动态规划(Dynamic Programming,DP)是运筹学的一个分支,是求解决策过程最优化的过程。20世纪50年代初,美国数学家贝尔曼(R.Bellman)等人在研究多阶段决策过程的优化问题时,提出了著名的最优化原理,从而创立了动态规划。动态规划的应用极其广泛,包括工程技术、经济、工业生产、军事以及自动化控制等领域,并在背包问题、生产经营问题、资金管理问题、资源分配问题、最短路径问题和复杂系统可靠性问题等中取得了显著的效果。

2 应用示例


动态规划问题中的划分问题示例:
arr[]={1,5,11,5}
输出:真
数组可以划分为{1、5、5}和{11}
arr[]={1,5,3}
输出:false
数组不能划分为等和集。
以下是解决此问题的两个主要步骤:
1) 计算数组的和。如果sum为奇数,则不可能有两个sum相等的子集,因此返回false。
2) 如果数组元素之和为偶数,则计算sum/2并找到sum等于sum/2的数组子集。
第一步很简单。第二步很关键,可以使用递归或动态规划来解决。
递归解决方案
下面是上面提到的第二步的递归属性。
让isSubsetSum(arr,n,sum/2)为函数,如果
有一个子集arr[0..n-1],其和等于和/2isSubsetSum问题可分为两个子问题
a) IsubSetSum()不考虑最后一个元素(将n减至n-1)
b) isSubsetSum考虑最后一个元素(通过arr[n-1]和n到n-1减少sum/2)
如果上述任何子问题返回true,则返回true。
isSubsetSum(arr,n,sum/2)=isSubsetSum(arr,n-1,sum/2)|| isSubsetSum(arr,n-1,sum/2-arr[n-1])

3 源代码

using System;
using System.Collections;
using System.Collections.Generic;namespace Legalsoft.Truffer.Algorithm
{public static partial class Algorithm_Gallery{#region 算法1private static bool Partition_Problem_IsSubset_Sum(int[] arr, int n, int sum){if (sum == 0){return true;}if (n == 0 && sum != 0){return false;}if (arr[n - 1] > sum){return Partition_Problem_IsSubset_Sum(arr, n - 1, sum);}return Partition_Problem_IsSubset_Sum(arr, n - 1, sum) || Partition_Problem_IsSubset_Sum(arr, n - 1, sum - arr[n - 1]);}static bool Partition_Problem_Solve(int[] arr, int n){int sum = 0;for (int i = 0; i < n; i++){sum += arr[i];}if (sum % 2 != 0){return false;}return Partition_Problem_IsSubset_Sum(arr, n, sum / 2);}#endregion#region 算法2private static bool Partition_Problem_IsSubset_Sum(int[] arr, int n, int sum, int[,] dp){if (sum == 0){return true;}if (n == 0 && sum != 0){return false;}if (dp[n, sum] != -1){return true;}if (arr[n - 1] > sum){return Partition_Problem_IsSubset_Sum(arr, n - 1, sum, dp);}dp[n, sum] = (Partition_Problem_IsSubset_Sum(arr, n - 1, sum, dp) || Partition_Problem_IsSubset_Sum(arr, n - 1, sum - arr[n - 1], dp)) ? 1 : -1;return dp[n, sum] > 0;}public static bool Partition_Problem_Solve_Second(int[] arr, int n){int sum = 0;for (int i = 0; i < n; i++){sum += arr[i];}if (sum % 2 != 0){return false;}int[,] dp = new int[n + 1, sum + 1];return Partition_Problem_IsSubset_Sum(arr, n, sum / 2, dp);}#endregion#region 算法3public static bool Partition_Problem_Solve_Third(int[] arr, int n){int sum = 0;for (int i = 0; i < n; i++){sum += arr[i];}if (sum % 2 != 0){return false;}bool[,] part = new bool[sum / 2 + 1, n + 1];for (int i = 0; i <= n; i++){part[0, i] = true;}for (int i = 1; i <= sum / 2; i++){part[i, 0] = false;}for (int i = 1; i <= sum / 2; i++){for (int j = 1; j <= n; j++){part[i, j] = part[i, j - 1];if (i >= arr[j - 1]){part[i, j] = part[i, j - 1] || part[i - arr[j - 1], j - 1];}}}return part[sum / 2, n];}#endregion#region 算法4public static bool Partition_Problem_Solve_Fourth(int[] arr, int n){int sum = 0;for (int i = 0; i < n; i++){sum += arr[i];}if (sum % 2 != 0){return false;}bool[] part = new bool[sum / 2 + 1];for (int i = 0; i <= sum / 2; i++){part[i] = false;}for (int i = 0; i < n; i++){for (int j = sum / 2; j >= arr[i]; j--){if (part[j - arr[i]] == true || j == arr[i]){part[j] = true;}}}return part[sum / 2];}#endregion}
}

4 源程序

using System;
using System.Collections;
using System.Collections.Generic;

namespace Legalsoft.Truffer.Algorithm
{
    public static partial class Algorithm_Gallery
    {
        #region 算法1
        private static bool Partition_Problem_IsSubset_Sum(int[] arr, int n, int sum)
        {
            if (sum == 0)
            {
                return true;
            }
            if (n == 0 && sum != 0)
            {
                return false;
            }
            if (arr[n - 1] > sum)
            {
                return Partition_Problem_IsSubset_Sum(arr, n - 1, sum);
            }

            return Partition_Problem_IsSubset_Sum(arr, n - 1, sum) || Partition_Problem_IsSubset_Sum(arr, n - 1, sum - arr[n - 1]);
        }

        static bool Partition_Problem_Solve(int[] arr, int n)
        {
            int sum = 0;
            for (int i = 0; i < n; i++)
            {
                sum += arr[i];
            }
            if (sum % 2 != 0)
            {
                return false;
            }
            return Partition_Problem_IsSubset_Sum(arr, n, sum / 2);
        }
        #endregion

        #region 算法2
        private static bool Partition_Problem_IsSubset_Sum(int[] arr, int n, int sum, int[,] dp)
        {
            if (sum == 0)
            {
                return true;
            }
            if (n == 0 && sum != 0)
            {
                return false;
            }
            if (dp[n, sum] != -1)
            {
                return true;
            }

            if (arr[n - 1] > sum)
            {
                return Partition_Problem_IsSubset_Sum(arr, n - 1, sum, dp);
            }

            dp[n, sum] = (Partition_Problem_IsSubset_Sum(arr, n - 1, sum, dp) || Partition_Problem_IsSubset_Sum(arr, n - 1, sum - arr[n - 1], dp)) ? 1 : -1;
            return dp[n, sum] > 0;
        }

        public static bool Partition_Problem_Solve_Second(int[] arr, int n)
        {
            int sum = 0;
            for (int i = 0; i < n; i++)
            {
                sum += arr[i];
            }
            if (sum % 2 != 0)
            {
                return false;
            }
            int[,] dp = new int[n + 1, sum + 1];

            return Partition_Problem_IsSubset_Sum(arr, n, sum / 2, dp);
        }
        #endregion

        #region 算法3
        public static bool Partition_Problem_Solve_Third(int[] arr, int n)
        {
            int sum = 0;
            for (int i = 0; i < n; i++)
            {
                sum += arr[i];
            }
            if (sum % 2 != 0)
            {
                return false;
            }

            bool[,] part = new bool[sum / 2 + 1, n + 1];
            for (int i = 0; i <= n; i++)
            {
                part[0, i] = true;
            }

            for (int i = 1; i <= sum / 2; i++)
            {
                part[i, 0] = false;
            }

            for (int i = 1; i <= sum / 2; i++)
            {
                for (int j = 1; j <= n; j++)
                {
                    part[i, j] = part[i, j - 1];
                    if (i >= arr[j - 1])
                    {
                        part[i, j] = part[i, j - 1] || part[i - arr[j - 1], j - 1];
                    }
                }
            }

            return part[sum / 2, n];
        }
        #endregion

        #region 算法4
        public static bool Partition_Problem_Solve_Fourth(int[] arr, int n)
        {
            int sum = 0;
            for (int i = 0; i < n; i++)
            {
                sum += arr[i];
            }
            if (sum % 2 != 0)
            {
                return false;
            }

            bool[] part = new bool[sum / 2 + 1];
            for (int i = 0; i <= sum / 2; i++)
            {
                part[i] = false;
            }

            for (int i = 0; i < n; i++)
            {
                for (int j = sum / 2; j >= arr[i]; j--)
                {
                    if (part[j - arr[i]] == true || j == arr[i])
                    {
                        part[j] = true;
                    }
                }
            }
            return part[sum / 2];
        }
        #endregion
    }
}
 

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

macbook pro 2018 安装 arch linux 双系统

文章目录 友情提醒关于我的 mac在 mac 上需要提前做的事情复制 wifi 驱动 在 linux 上的操作还原 wifi 驱动连接 wifi 网络磁盘分区制作文件系统挂载分区 使用 archinstall 来安装 arch linux遗留问题 友情提醒 安装 archl linux 的时候&#xff0c;mac 的键盘是没法用的&#…

【开源】JAVA+Vue.js实现创意工坊双创管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 管理员端2.2 Web 端2.3 移动端 三、系统展示四、核心代码4.1 查询项目4.2 移动端新增团队4.3 查询讲座4.4 讲座收藏4.5 小程序登录 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的创意工坊双创管理…

解读电影级视频生成模型 MovieFactory

Diffusion Models视频生成-博客汇总 前言&#xff1a;MovieFactory是第一个全自动电影生成模型&#xff0c;可以根据用户输入的文本信息自动扩写剧本&#xff0c;并生成电影级视频。其中针对预训练的图像生成模型与视频模型之间的gap提出了微调方法非常值得借鉴。这篇博客详细解…

匈牙利算法

匈牙利算法&#xff1a;是一种在多项式时间内求解任务分配问题的组合优化算法&#xff0c;并推动了后来的原始对偶方法 时间复杂度&#xff1a;O(nm) 适用场景&#xff1a;二分图的最大匹配 核心思想&#xff1a;增广路径&#xff0c;即当左边集合的点1匹配右边的点2为已匹配…

IPv6扩展头(四)——分片头

分片头部&#xff08;Fragment Header&#xff09;用于IPv6源节点向目的节点发送一个大于路径MTU的数据报。 一、优势 IPv6 分片头具有多种优势&#xff0c;可提高网络效率&#xff0c;包括减少数据包延迟和减少网络拥塞。使用 IPv6 分片头&#xff0c;数据包在源处而不是中间…

光谱整形1

华为张德江&#xff1a;下一代光传送网将走向400G80波WDM系统_通信世界网 (cww.net.cn) 张德江指出&#xff0c;400G WDM系统具有三大基本特征&#xff1a;支持400G80波&#xff0c;单纤32T超大容量&#xff0c;传输距离与100G相当&#xff1b;支持32维以上的光交叉&#xff1…

Python实例☞数据类型及运算符案例

实例一&#xff1a; ❶要求☞从键盘获取一个4位整数&#xff0c;并分别输出个、十、百、千位 ❷程序代码☞ ①第一种方法 print(请输入一个4位整数&#xff1a;) xeval(input()) print(个位数为&#xff1a;,x%10) print(十位数为&#xff1a;,(x//10)%10) print(百位数为&am…

4.1k star,官方出品的redis桌面管理工具——redislnsight

导航 令人抓狂的大key加载RedisInsight 简介RedisInsight的亮点GitHub 地址安装和使用RedisInsight 下载安装 使用RedisInsight redis数据库可视化直观的CLI&#xff08;Command-Line Interface&#xff09;日志分析和命令分析 结语参考 令人抓狂的大key加载 工欲善其事必先利…

利用GPT开发应用003:GPT分词和预测

文章目录 一、概率问题二、令牌&#xff08;分词&#xff09;三、预测 一、概率问题 像 GPT 这样的大型语言模型接收一个提示&#xff0c;并返回通常在上下文中有意义的输出。例如&#xff0c;提示可以是“今天天气很好&#xff0c;所以我决定”&#xff08;“The weather is n…

检测螺栓扭矩的方法有哪些——SunTorque智能扭矩系统

螺栓扭矩的检测是确保螺栓连接紧固程度和安全性的重要环节。正确的扭矩检测能够预防螺栓松动、断裂等潜在风险&#xff0c;从而保障设备和结构的稳定运行。SunTorque智能扭矩系统接下来将详细介绍螺栓扭矩的检测方法。 螺栓扭矩的检测是确保螺栓连接紧固程度和安全性的重要环节…

什么是VR全息投影技术|元宇宙文旅|VR设备购买

VR全息投影技术是一种结合了虚拟现实&#xff08;VR&#xff09;和全息投影技术的创新技术&#xff0c;旨在创造出更加沉浸式和真实感的体验。 在这种技术中&#xff0c;用户可以通过戴上特殊的头戴式显示器&#xff08;如VR头显&#xff09;进入虚拟现实世界&#xff0c;同时通…

Spark Core

Spark Core 一、Spark RDD RDD概述 1.RDD基础 2.RDD源代码描述 3.RDD特性 4.Spark宽窄依赖 RDD创建 在驱动器中创建RDD 1.parallelize 读取外部数据集创建RDD 2.textFile RDD操作 缓存rdd到内存 1.RDD转化操作 2.常见的转化操作 3.RDD行动操作 4.常见的行动操作 Spark…