我正在研究以下问题:
给定一组非负的不同整数,并给出一个值m,确定给定集合是否有一个子集,其和可被m整除。
输入:输入的第一行包含一个整数T,表示测试用例的数量。然后是T个测试用例。每个测试用例的第一行包含一个整数N和M,其中N表示数组的大小,M是我们必须检查整除性的数字。每个测试用例的第二行包含N个空格分隔的整数,表示数组A[]的元素。
#include <iostream>
#include<unordered_map>
using namespace std;
bool find_it(int a[],int &m,int n,int sum) {
if ((sum%m)==0 && sum>0)
return true;
if (n==0)
return false;
return find_it(a,m,n-1,sum) || find_it(a,m,n-1,sum-a[n-1]);
}
int main() {
int tc;
cin >> tc;
while (tc--) {
int n,m;
cin >> n >> m;
int a[n];
int sum = 0;
for (int i=0;i<n;i++) {
cin >> a[i];
sum += a[i];
}
bool answer = find_it(a,m,n,sum);
cout << answer << "\n";
}
return 0;
}
#include <iostream>
#include<unordered_map>
using namespace std;
bool find_it(
int a[], int &m, int n, int sum,
unordered_map<int,unordered_map<int,bool>> &value,
unordered_map<int,unordered_map<int,bool>> &visited){
if ((sum%m)==0 && sum>0)
return true;
if(n==0)
return false;
if(visited[n][sum]==true)
return value[n][sum];
bool first = false,second = false;
first = find_it(a,m,n-1,su1m,value,visited);
if(sum<a[n-1])
{
second=false;
}
else
second = find_it(a,m,n-1,sum-a[n-1],value,visited);
visited[n][sum] = true;
value[n][sum] = first || second;
return value[n][sum];
}
int main() {
int tc;
cin >> tc;
while (tc--) {
int n,m;
cin >> n >> m;
int a[n];
int sum = 0;
for (int i=0;i<n;i++) {
cin >> a[i];
sum+=a[i];
}
unordered_map<int,unordered_map<int,bool>> value;
unordered_map<int,unordered_map<int,bool>> visited;
cout << find_it(a,m,n,sum,value,visited) << "\n";
}
return 0;
}
首先,您可以将问题简化为模M
问题,因为当切换到模M
字段时,整数的属性不会改变。可以很容易地证明,被m
整除就等于与0
modm
相同。
我首先将所有这些数字转换成它们的对应模m
,并通过考虑a_i
,2*a_i
,3*a_i
,······在rep_a_i*a_i
之前,它们都是modm
。最后,得到一个最多包含M
元素的约简集。然后消除那里所有的零,因为它们对和没有贡献。这很重要,有两个原因:
O(a^n)
的背包问题(NP-complete)转换为O(K)
问题,因为它的复杂性不取决于集合的元素数,而是M
.a_i
遵循具有k>2
问题的其余部分是一个背包问题(它是NP完全的)或它的一个P变体。
如果您没有做到这一点(不能将其简化为一个简单的背包问题),那么您必须减少a_i
的数量,以便指数时间得到一个最小指数:)
(@MSS在评论中要求精化)假设您有M=8
,列表为1 2 4 6 12 14 22
。在简化modm
之后,列表仍然为:1 2 4 6 4 6 6
,其中6重复了三次。我们必须考虑6的三个可能的重复,因为它们可以帮助得到一个和,但不能更多(目前),让我们考虑6*1=6
,6*2=12
和6*3=18
,第一个是原始的6
,第二个对4
进行第三次重复(因此我们需要在列表中考虑34
),第三个转换为2
。现在,列表中有1 2 4 6 4 4 2
。我们对4
重复做同样的处理(两个4
运行到8
,这是0
m,不影响和,但我们必须保留一个这样的0
,因为这意味着您通过重复的数字得到目标m
)进入1 2 4 6 0 2 2
=>1 2 4 6 0 2
=(reorder)=>0 1 2 2 4 6
=>0 1 2 2 4 6这应该是最后要考虑的名单。因为它有一个
0
,所以您先验地知道有一个这样的和(在本例中,对于原始列表的4
和12
数字,您得到的是包括两个4
。
问题内容: 我正在研究将RequestDTO发送到Web服务的类。我需要先验证请求,然后再发送。 可以从3个不同的地方发送请求,每个“ requesttype”都有不同的验证规则,例如request1必须具有名称和电话号码,request2必须具有地址,等等) 我有一个DTO,其中包含很长的字段列表(名称,地址,城市,电话号码等),无论请求是哪种类型,DTO都发送相同的消息。 我创建了3种不同的验
帮助我减少这个程序的时间复杂性 输出:为每个测试用例输出这样的对的数量。 约束条件:T≤10;N≤100000;A[i]≤1000000 示例输入(明文链接)
如何降低给定代码段的复杂性?我在Sonarqube中得到了这个错误-->重构这个方法,将其认知复杂度从21降低到允许的15。
上篇的标记算法中,谈到这个O(K)的算法是一个指数级复杂度的算法,其实对那道题目本身来说,K是固定的,既然不是输入,那也无所谓复杂度,之所以有O(K)这种说法,是把K当做一种输入了,这是看待输入的角度问题,倒不用深究。考虑一个更简化的算法(python代码,设输入n是正整数): def f(n): i = 0 while i < n: i += 1
这个isValid()方法最多有6个属性可以设置以便进行验证。如果没有设置特定属性,则不需要对其进行验证。逻辑似乎是工作的方式,我希望它的工作。如何降低此方法的布尔表达式复杂性?
在Sonarqube上,我把这个问题作为一个关键问题,有人能帮我解决这个问题吗。这里是代码的详细信息,请让我知道如何用开关情况重构此代码: