在我的算法中找到最大的子集的缺陷,其中每对的和不会除以K?

时间:2016-08-03 05:56:39

标签: c# algorithm linq time-complexity complexity-theory

我发表了关于我的逻辑是什么的评论。它应该起作用的方式是,例如,如果我们有K=3S={1,7,2,4},那么每个对的总和不会除K的最大子集1}}是{1,7,4}

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

class Solution
{
    static void Main(String[] args)
    {
        int k = Int32.Parse(Console.ReadLine().Split(' ')[1]);
        var S = Array.ConvertAll(Console.ReadLine().Split(' '), Int32.Parse);

        // first get all pairs in S whose sum doesn't divide k, 
        // each pair in their own subset set of S
        var subsets = from i in S
                      from j in S
                      where i < j && ((i + j) % k != 0)
                      select new HashSet<int>() { i, j };

        // for each subset, for each number in the original set 
        // not already in the subset, if the number summed with
        // every numer in the subset doesn't divide k, add the
        // number to the subset
        foreach(var ss in subsets)
             foreach(int n in S.Where(q => !ss.Contains(q)))
                if(ss.All(m => (m + n) % k != 0))
                   ss.Add(n);

        // get the size of the largest subset, print to console
        int max = subsets.Select(ss => ss.Count).Max();
        Console.WriteLine(max);
    }
}

3 个答案:

答案 0 :(得分:2)

您的问题算法可能是错误的,但意外的行为是由于代码中的错误造成的。 (但即使你修复它,我认为这对于在线评判来说太慢了,你也可能会错过一些棘手的案例,你可以尝试提交它)。

HashSet对象subsets未更新,因为当您致电Add时,整数会添加到另一个HashSet的副本中。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;


public class Test
{
    public static void Main(String[] args)
    {
        ...
       foreach(var ss in cnt){
             foreach(int n in S.Where(q => !ss.Contains(q)))
                if(ss.All(m => (m + n) % k != 0)){
                   ss.Add(n);
                }
          // Log here, you will see the size is updated to 3
            Console.WriteLine(ss.Count);
        }
        // Log here, it is still printing 2 !         
        foreach(var ss in cnt)
             Console.WriteLine(ss.Count);
        // get the size of the largest subset, print to console
        int max = ...
        Console.WriteLine(max);
    }
}

一个简单的解决方法是首先新建一个全局的hashset列表,并更新该列表

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;


public class Test
{
    public static void Main(String[] args)
    {
        int k = Int32.Parse(Console.ReadLine().Split(' ')[1]);
        var S = Array.ConvertAll(Console.ReadLine().Split(' '), Int32.Parse);
        List<HashSet<int>> cnt = new List<HashSet<int>>();
        // first get all pairs in S whose sum doesn't divide k, 
        // each pair in their own subset set of S
        cnt = (from i in S
                      from j in S
                      where i < j && ((i + j) % k != 0)
                      select new HashSet<int>() { i, j }).ToList();

        // for each subset, for each number in the original set 
        // not already in the subset, if the number summed with
        // every numer in the subset doesn't divide k, add the
        // number to the subset

        foreach(var ss in cnt){
             foreach(int n in S.Where(q => !ss.Contains(q)))
                if(ss.All(m => (m + n) % k != 0)){
                   ss.Add(n);
                }
        }

        // get the size of the largest subset, print to console
        int max = cnt.Max(ss => ss.Count);
        Console.WriteLine(max);
    }
}

但是,这个问题可以在O(k)中轻松解决(如果不计算I / O时间O(N)

这是我在C ++中接受的代码

#include<bits/stdc++.h>
using namespace std;
int n,k,a,c[105] = {0},ans=0;
int main() {
    cin >> n >> k;
    for(int i=0; i<n;i++) cin >> a, c[a%k]++;

    for(int i=1; i<=k/2; i++){
        if(k%2 == 0 && i==k/2 && c[i]) ans++;
        else ans += max(c[i], c[k-i]);
    }
    if(c[0] && ans) ans++;
    if(!ans) ans++;
    cout << ans << endl;
    return 0;
}

这背后的概念是模运算:

(a+b)%k = 0 is equavalent to (a%k + b%k)%k = 0

实际上,我们只计算模块k等于0,1,2 ... k-1的元素数量,将它们存储在c[0], c[1]...c[k-1]

然后逻辑地说,c[1]&amp; c[k-1]不能一起选择,因此我们选择计数较大的那个。同样,c[2] & c[k-2]不能一起选择,等等。

但是有一些特殊情况,你可能会看到我的代码并查看它。

了解这个问题的另一个棘手的地方是(我认为这是一个糟糕的书面问题陈述),如果结果集大小是1,那么它总是一个有效的集合,即使唯一的元素可以被k整除。 (即,ans永远不会是0)

答案 1 :(得分:0)

在你的第二个循环中,当你写ss.Add(n);时 你将'n'添加到hashset ss的副本中。

所以在foreach部分之后,subsets仍然保留了之前的部分。

您可以手动计算foreach中的最大值作为快速解决方案

答案 2 :(得分:-1)

使用您的方法,您将找出满足条件的所有数字的子集,但您不要将数字子集添加到整体subsets。因此,当您寻找最大的子集时,您将找不到正确的子集。

    foreach(var ss in subsets)
    {
         foreach(int n in S.Where(q => !ss.Contains(q)))
         {
            if(ss.All(m => (m + n) % k != 0))
               ss.Add(n);
         }
     //Add the subset ss to subsets or replace it
    }