割り切れないペアごとの最大サブセット


8

数値のセットがあり、その要素の任意の2つの要素の合計が整数割り切れないように最大サブセットを計算したいと考えています。この問題を解決しようとしましたが、効率的な応答ではない2次の解を見つけました。。ここで、は要素の数、は定数です。二次解より良いですか?K < 100 N < 10000 N KK
K<100,N<10000NK


あなたの解決策を説明できますか?より良い解決策があると確信していますか?編集はあなたの意図を保存しましたか?
悪の

このリンクでいくつかの解決策見つけることができます。
Gadheyan .ts 2016年

@ Gadheyan.tsあなたが言及した問題は、この問題の非常に特殊なケースです。この問題は、数の所定のセットは、の形態であり、ここでは数値の任意のセットを有します。あなたが述べた問題はO 1 )で解決できます。{1,2,,N}O(1)
orezvani 2016年

回答:


13

実際、これには線形時間アルゴリズムがあります。基本的な数論の概念のみを使用する必要があります。二つの数、所与の及びN 2、それらの和はに割り切れるKそれらの残りの合計が割り切れる場合のみ、K。言い換えると、n1n2KK

K(n1+n2)        K((n1 mod K)+(n2 mod K)).

あなたが考慮する必要があることを第二のコンセプトはつまり、2つの数の和であるKそのうちの一つが、より厳密に小さくされていない場合にのみ、K / 2、その他は一切未満であるK / 2。言い換えると、r1r2KK/2K/2

r1+r2=K      r1<K/2, r2K/2      (r1r2, w.l.g. r1<r2).

2つの数の和であれば、あなたが考慮する必要があることを第三の概念は、つまりあるKから、彼らの両方がずれるK / 2 - 1特定することによりK K / 2 、すなわち、r1r2KK/21kK/2

r1+r2=K      kK/21   such that   r1=K/21k, r2=K/2+k.

したがって、3番目の概念のevey 場合、r 1またはr 2のいずれかをソリューションセットに含める必要がありますが、両方を含めることはできません。実際にKで割り切れる数値の1つを入れることができます。Kが偶数の場合、余りがK / 2である数値を1つだけ追加できます。kr1r2KKK/2

したがって、ここにアルゴリズムがあります。

セット所与の、の溶液を設定見つけるせてSをN={n1,n2,,nN}S,

  1. 検討R={r1=(n1 mod K),r2=(n2 mod K),,rN=(nN mod K)}
  2. S
  3. 以下のためのK / 2 - 1k1K/21
  4. もしcount(R,k)count(R,Kk)
  5. すべてのSに追加します。たとえば、r i = kniSri=k
  6. そうしないと:
  7. すべてのSに追加します。たとえば、r i = K kniSri=Kk
  8. Sにを1つだけ追加して、r i = 0にするniSri=0//存在する場合
  9. もし偶数であります:K
  10. Sにを1つだけ追加して、r i = K / 2にするniSri=K/2//存在する場合
  11. 出力S

アルゴリズムはかなり長いですが、アイデアは非常に簡単です。


@DW私はと仮定しました。私は偶数を避けるために、そのような仮定を意図的に入れました。以下を追加しました: "wlg r 1 < r 2 "r1r2r1<r2
orezvani

@DWそれは完全に偶数を避けません。先に進むと、なぜ私がそのような概念/補題を使用したのかがわかります。基本的に、偶数場合、一部のn iの残りが正確にK / 2である場合、それらのn iの1つのみに関心があります(複数指定すると、質問の条件に違反します)。 。そのため、そのようなn iをすべてその条件で個別に扱いました。KniK/2nini
orezvani 2016年

@DW私は wlgを入れました。それは本当に不必要だと思いますが、私は慣例の問題のためだけにそれを置きました。r1<r2
orezvani 2016年

わかりました、あなたの今の意味がわかります!説明していただきありがとうございます。
DW

1

すべての異なる自然数を含むサイズnのセットSを考えます。このセットから最大のサブセットを形成する必要があります。基本的な係数プロパティを使用し、いくつかの控除を追加して問題を解決します。皆さんのお役に立てれば幸いです。

任意の2つの自然数N1およびN2の場合:(N1 + N2)mod(K)=(R1 + R2)mod(K)ここで、R1 = N1modKおよびR2 = N2%K。1.(N1 + N2)modK = 0の場合、(R1 + R2)%K = 0を意味します。2.つまり、R1 + R2はK、2K、3Kのいずれかに等しくなければなりません。...3.しかし、R1は0とK-1の間にあり、R2も同じです。つまり、それらの合計はK-1 + K-1を超えることはできません= 2(K-1)。4. 2と3から、R1 + R2はKに等しい必要があると結論付けることができます。5. R1 + R2 = Kの場合、両方がK / 2に等しい必要があります(Kが偶数の場合のみ可能)またはそれらの1つはfloor [K / 2]より小さく、1つは同じより大きくなければなりません。6. R1 = TおよびR2 = KTと仮定します。残りがR1であるSから任意の数N1を、残りがR2であるSから任意の数N2を取得すると、それらの合計はKで割り切れます。残りがR1の数値、または残りがR2の数値。ただし、両方は含まれません。

ここで、インデックス0からK-1までのサイズKの配列Rを構築するとします。各インデックスの要素は、(Sで除算した)剰余がインデックス番号に等しいセットSの数を示します。合計がKで割り切れるので、余りが0の3つ以上の数は使用できません。したがって、カウンターをmin(R [0]、1)で初期化する必要があります。T = 1からT

C ++での同じアルゴリズムのコードは次のとおりです。

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;


int main() {

    int n,k;
    cin>>n>>k;
    vector <int> a(n);
    vector <int> r(k,0);
    for(int i=0;i<n;i++)
    {   
        cin>>a[i];
        r[a[i]%k]++;
    }
    int ctr=min(1,r[0]);
    for(int a=1;a<(k/2+1);a++)
        {
            if(a!=k-a)
                ctr+=max(r[a],r[k-a]);
        }
    if(k%2==0&&r[k/2]!=0)
        ctr++;
    cout<<ctr;
    return 0;
}

コードを疑似コードに変換できますか?
邪悪な

1. k、nを読み取る2.サイズnとkの2つの配列AとRを作成する3. i = 0、ctr = 0、a = 1 4. while(i <n)はA [i] R [A [を読み取るi]%k] ++ i = i + 1 endwhile 5. ctr = minimum(1、R [0])6. while(a <k / 2 + 1)do if(a!= ka)ctr = ctr + maximum(R [a]、R [ka])endif a = a + 1 endwhile 7. if(kは、2で除算され、R [k / 2]がゼロ以外の場合、余りは0になります)ctr = ctr + 1 8. print ctr 9. End
Dhruva Bhagdikar 2017

私は投稿で、編集を使用することにより、不便をおかけして申し訳ありませんでした。また、疑似コードをありがとうございます。

0

最初にサブセット配列のサイズのみをカウントするC#コードと、(ハッシュ)サブセット全体を含む別のコードに変換しようとしました。

カウント:

static int nonDivisibleSubset(int k, int[] S)
{
    var r = new int[k];

    for (int i = 0; i < S.Length; i++)
        r[S[i] % k]++;

    int count = Math.Min(1, r[0]); 

    if (k % 2 == 0 && r[k / 2] != 0) 
        count++;                                    

    for (int j = 1; j <= k / 2; j++) 
    {                                                         
        if (j != k - j)
            count += Math.Max(r[j], r[k - j]);
    }

    return count;
}

サブセットあり:

static int nonDivisibleSubset(int K, int[] S)
{
    var r = new HashSet<int>();
    var d = S.GroupBy(gb => gb % K).ToDictionary(Key => Key.Key, Value => Value.ToArray());

    for (int j = 1; j <= K / 2; j++)
    {
        var c1 = d.GetValueOrDefault(j, new int[0]);
        var c2 = d.GetValueOrDefault(K - j, new int[0]);

        if (c1.Length == c2.Length) continue;

        r.UnionWith(c1.Length > c2.Length ? c1 : c2);
    }

    if (d.ContainsKey(0))
        r.Add(d[0].Max());

    if (K % 2 == 0 && d.ContainsKey(K / 2))
        r.Add(d[K / 2].Max());

    return r.Count;
}

1
これはコーディングサイトではありません。
Yuval Filmus

これは数学のサイトですか?
BigChief 2018

サイトの正確な範囲を定義することは困難です。周りを見回して、どの質問がクローズされ、どれがクローズされないかを確認できます。
Yuval Filmus

私の意図は、すでに投稿されたコードにさらに深さを追加することでした。後者のコードブロックは、サブセットのサイズだけを返すのではなく、サブセット全体を明示的に最大化するサブセットを返します。うまくいけば、これは目の前の問題を理解しようとしている人にとって役に立ちます。また、正しさについてフィードバックをいただければ幸いです。コードや数学の方程式を投稿することは、いくつかの同等性を持っていますか?
BigChief 2018

投稿コードは通常眉をひそめられます。疑似コードまたはテキストによる説明をお勧めします。
Yuval Filmus
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.