卓越飞翔博客卓越飞翔博客

卓越飞翔 - 您值得收藏的技术分享站
技术文章16601本站已运行3320

子集相等性是NP完全的

子集相等性是NP完全的

子集对应,也称为“子集总计”问题,是一个示例性的 NP 完全计算问题。给定一堆数字和一个客观价值,任务是确定是否存在其总数等于客观价值的数字子集。该问题的 NP 顶峰源于其通过多项式时间递减来解决各种其他 NP 完全问题的能力。不管其简单的定义如何,没有一种有效的计算可以解决所有事件的“子集对应”,这使得它在假设的软件工程和简化中具有重要意义,并且在不同领域(如密码学、资产分配和动态问题)具有功能应用。

使用的方法

  • 子集总和的减少

  • 从 3SAT 减少

从子集总和中减少

处理“子集公平性”是 NP 完成问题的一种方法是显示显着的 NP 完成问题(“子集总数”问题)的减少。

算法

  • 给定一个“子集聚合”问题的案例,它是一堆整数 S 和一个价值 T 的目标。

  • 使用类似的集合 S 和目标自尊 2T 来制作“子集权益”问题的另一个案例。

  • 如果在“子集聚合”问题中存在 S 的子集汇总为 T,那么此时,“子集均匀性”问题中将存在一个汇总为 T 的子集2T 通过添加与其自身相似的子集。

  • 假设在“子集总计”问题中不存在 S 的子集汇总为 T,那么在“子集公平性”问题中也不存在汇总为 2T 的子集,因为任何具有总计的子集低于2T的与其自身相加不能超过2T。

  • 这种下降表明解决“子集公平性”问题与解决“子集聚合”问题几乎一样困难,使其成为 NP 完全问题。

示例

#include <iostream>
#include <vector>
using namespace std;

bool isSubsetSum(vector<int>& set, int n, int sum) {
   if (sum == 0) return true;
   if (n == 0) return false;

   if (set[n - 1] > sum) return isSubsetSum(set, n - 1, sum);

   return isSubsetSum(set, n - 1, sum) || isSubsetSum(set, n - 1, sum - set[n - 1]);
}

bool isSubsetAggregateReduction(vector<int>& set, int n, int sum) {
   return !isSubsetSum(set, n, sum) && !isSubsetSum(set, n, 2 * sum);
}

int main() {
   vector<int> set = {3, 34, 4, 12, 5, 2};
   int sum = 18; 
   if (isSubsetAggregateReduction(set, set.size(), sum)) {
      cout << "No subset exists in Subset Aggregate issue that sums to " << sum << " and no subset exists that sums to " << 2 * sum << " by adding the same subset with itself." << endl;
   } else {
      cout << "There exists a subset in Subset Aggregate issue that sums to " << sum << " or a subset in Subset Equity issue that sums to " << 2 * sum << " by adding the same subset with itself." << endl;
   }

   return 0;
}

输出

There exists a subset in Subset Aggregate issue that sums to 18 or a subset in Subset Equity issue that sums to 36 by adding the same subset with itself.

从 3SAT 减少

另一种方法是通过直接从一个已知的 NP 完全问题(例如 3SAT 问题)中减去它来证明“子集对应”是 NP 完成的。

算法

  • 给出了 3SAT 问题的示例,其中包含一个联合普通结构中的布尔配方,每个条件具有三个文字。

  • 用一堆整数和目标值再讨论一下“子集均匀性”问题,如下所示:

  • a.对于 3SAT 方程中的每个变量,在集合中创建一个值为 1 的数字。

    b.对于 3SAT 方程中的每个附加条件,在集合中生成一个值为 2 的数字。

    c.将目标值设置为 3SAT 配方中的全部附加条件和所有因素的全部数量。

  • 如果 3SAT 方案可满足,则“子集均匀性”问题中存在一个子集,该子集通过为每个已满足的条件选择一个变量来总结目标值。

  • 如果 3SAT 配方无法满足,那么“子集对应”问题中就没有子集可以概括为目标值,因为任何合法子集都必须包含不少于一个值为 2 的整数,与已履行的条款相关。

  • 由于已知 3SAT 问题是 NP 完成的,因此这种下降表明“子集股权”的 NP 顶峰。

示例

#include <iostream>
#include <vector>
using namespace std;

bool ThreeSAT_Satisfiable(const vector<vector<int>>& clauses) {
   return false;
}

class SubsetUniformity {
private:
   vector<int> numbers;
   int targetValue;

public:
   SubsetUniformity(const vector<int>& vars, const vector<int>& clauses) {
      for (int v : vars) {
         numbers.push_back(1);
      }
      for (int c : clauses) {
         numbers.push_back(2);
      }
      targetValue = vars.size() + clauses.size();
   }

   bool isSubsetSumPossible(int idx, int sum) {
      if (sum == targetValue) {
         return true;
      }
      if (idx >= numbers.size() || sum > targetValue) {
         return false;
      }
      return isSubsetSumPossible(idx + 1, sum) || isSubsetSumPossible(idx + 1, sum + numbers[idx]);
   }

   bool hasSolution() {
      return isSubsetSumPossible(0, 0);
   }
};

int main() {
   vector<vector<int>> clauses = {
      {1, 2, -3},
      {-1, -2, 3},
      {-1, 2, 3}
   };

   bool isSatisfiable = ThreeSAT_Satisfiable(clauses);
   SubsetUniformity su(clauses[0], clauses[1]);

   cout << "3SAT Formula is " << (isSatisfiable ? "satisfiable." : "not satisfiable.") << endl;
   cout << "Subset Uniformity has " << (su.hasSolution() ? "a" : "no") << " solution." << endl;

   return 0;
}

输出

3SAT Formula is not satisfiable.
Subset Uniformity has a solution.

结论

这两种方法都表明“子集权益”或“子集聚合”问题是 NP 完成的,因此,跟踪有效的计算来解决所有示例的问题是不可能的。科学家经常利用动态规划或其他估计程序来有效地解决此问题的可行情况。

卓越飞翔博客
上一篇: 如何在Python中获取字典中的下一个键?
下一篇: 返回列表

相关推荐

留言与评论(共有 0 条评论)
   
验证码:
隐藏边栏