Tập hợp con tối đa theo cặp không chia hết cho


8

Tôi có một tập hợp các số, và muốn tính toán tập hợp con tối đa sao cho tổng của bất kỳ hai trong số các yếu tố của nó là không chia hết cho một số nguyên . Tôi đã cố gắng giải quyết vấn đề này, nhưng tôi đã tìm ra giải pháp bậc hai, đó là phản ứng không hiệu quả. , trong đó N là số phần tử và K được cho không đổi. Có tốt hơn giải pháp bậc hai?K < 100 , N < 10000 N KK
K<100,N<10000NK


Bạn có thể mô tả giải pháp của bạn? Bạn có chắc chắn tồn tại giải pháp tốt hơn? Liệu chỉnh sửa có bảo tồn ý định của bạn?
Ác

Bạn có thể tìm thấy một số giải pháp trên liên kết này .
Gadheyan .ts

@ Gadheyan.ts vấn đề mà bạn đề cập là một trường hợp rất đặc biệt của vấn đề này. Trong bài toán đó, bộ số đã cho có dạng , trong khi ở đây chúng ta có một bộ số tùy ý. Vấn đề mà bạn đề cập có thể được giải quyết trong . O ( 1 ){1,2,,N}O(1)
orezvani

Câu trả lời:


13

Quả thực có một thuật toán thời gian tuyến tính cho việc này. Bạn chỉ cần sử dụng một số khái niệm lý thuyết số cơ bản. Với hai số và , tổng của chúng chia hết cho , chỉ khi tổng dư của họ là chia hết cho . Nói cách khác,n 2 K Kn1n2KK

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

Khái niệm thứ hai mà bạn cần xem xét là, tổng của hai số là , chỉ khi một trong số chúng nhỏ hơn và số kia không nhỏ hơn . Nói cách khác, K K / 2 K / 2r1r2KK/2K/2

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

Khái niệm thứ ba mà bạn cần xem xét là, nếu tổng của hai số là , cả hai đều lệch khỏi bởi một , I E, K K / 2 - 1 k K / 2 r1r2KK/21kK/2

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

Vì vậy, đối với evey trong khái niệm thứ ba, bạn cần đặt hoặc trong bộ giải pháp, nhưng không phải cả hai. Bạn được phép đặt một trong các số thực sự chia hết cho và nếu là số chẵn, bạn chỉ có thể thêm một số mà phần còn lại của nó là .r 1 r 2 K K K / 2kr1r2KKK/2

Do đó, đây là thuật toán.

Đặt một bộ , hãy tìm bộ giải phápS ,N={n1,n2,,nN}S,

  1. Hãy xem xétR= ={r1= =(n1 mod K),r2= =(n2 mod K),,rN= =(nN mod K)}
  2. S
  3. cho đến :K / 2 - 1k1K/2-1
  4. nếu :cobạnnt(R,k)cobạnnt(R,K-k)
  5. thêm tất cả vào , sao choS r i = knTôiSrTôi= =k
  6. khác:
  7. thêm tất cả vào , sao choS r i = K - knTôiSrTôi= =K-k
  8. chỉ thêm một vào sao cho // nếu tồn tạiS r i = 0nTôiSrTôi= =0
  9. nếu chẵn:K
  10. chỉ thêm một vào sao cho // nếu tồn tạiS r i = K / 2niSri=K/2
  11. Đầu raS

Thuật toán khá dài, nhưng ý tưởng rất đơn giản.


@DW Tôi giả sử rằng . Tôi cố tình đặt giả định đó để tránh số chẵn; Tôi đã thêm vào như sau: "wlg "r1r2r1<r2
orezvani

@DW Nó không hoàn toàn tránh các số chẵn. Nếu bạn tiến hành, bạn sẽ thấy lý do tại sao tôi đã đặt khái niệm / bổ đề như vậy. Về cơ bản, đối với số chẵn , nếu phần còn lại của một số chính xác là , thì chúng tôi chỉ quan tâm đến một trong số đó (nếu chúng tôi đặt nhiều hơn một, chúng tôi sẽ vi phạm điều kiện của câu hỏi). Đó là lý do tại sao, tôi đã xử lý tất cả các như vậy với tình trạng đó một cách riêng biệt. KniK/2nini
orezvani

@DW Tôi đặt wlg cho . Tôi nghĩ rằng điều đó thực sự không cần thiết nhưng tôi đặt nó chỉ là vấn đề của các công ước. r1<r2
orezvani

OK, tôi hiểu ý của bạn bây giờ! Cảm ơn vì đã giải thích.
DW

1

Xét một tập hợp S có kích thước n chứa tất cả các số tự nhiên riêng biệt. Chúng ta phải tạo thành tập hợp con tối đa từ tập hợp này. Chúng tôi sử dụng một thuộc tính mô đun cơ bản và thêm một vài khoản khấu trừ vào nó để giải quyết vấn đề. Tôi hy vọng nó hữu ích cho tất cả các bạn.

Với hai số tự nhiên N1 và N2: (N1 + N2) mod (K) = (R1 + R2) mod (K) trong đó R1 = N1modK và R2 = N2% K. 1. Nếu chúng ta (N1 + N2) modK = 0 thì có nghĩa là (R1 + R2)% K = 0. 2. Điều đó có nghĩa là R1 + R2 phải bằng K, 2K, 3K .... 3. Nhưng R1 nằm giữa 0 & K-1 và R2 cũng vậy, có nghĩa là tổng của chúng không thể vượt quá K-1 + K-1 = 2 (K-1). 4. Từ 2 và 3, chúng ta có thể kết luận rằng R1 + R2 phải bằng K. 5. Hơn nữa nếu R1 + R2 = K có nghĩa là cả hai đều phải bằng K / 2 (chỉ có thể nếu K chẵn) hoặc một trong số chúng phải nhỏ hơn sàn [K / 2] và một lớn hơn cùng tầng. 6. Giả sử R1 = T và R2 = KT, nếu chúng ta lấy bất kỳ số N1 nào từ S có phần dư là R1 và bất kỳ số N2 nào từ S có phần dư là R2 thì tổng của chúng sẽ chia hết cho K. Do đó, tập con Giải pháp có thể có các số đó các số có số dư R1 hoặc các số còn lại R2 nhưng không phải cả hai.

Bây giờ Giả sử chúng ta xây dựng một mảng R có kích thước K với chỉ số từ 0 đến K-1, Phần tử trong mỗi chỉ mục biểu thị số lượng số trong tập S với phần còn lại (trên phép chia với K) bằng số chỉ mục. Chúng ta không thể có nhiều hơn 2 số với số còn lại là 0 vì tổng của chúng sẽ chia hết cho K do đó chúng ta phải khởi tạo bộ đếm của mình với min (R [0], 1). Cho T = 1 đến T

Mã cho cùng một thuật toán trong C ++ như dưới đây:

#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;
}

Bạn có thể dịch mã của bạn thành mã giả?
Ác

1. Đọc k, n 2. Tạo hai mảng A và R có kích thước n và k 3. i = 0, ctr = 0, a = 1 4. while (i <n) làm đọc A [i] R [A [ i]% k] ++ i = i + 1 cuối 5. ctr = tối thiểu (1, R [0]) 6. while (a <k / 2 + 1) làm if (a! = ka) ctr = ctr + tối đa (R [a], R [ka]) endif a = a + 1 cuối cùng 7. if (k cho 0 phần dư khi chia cho 2 và R [k / 2] không bằng 0) ctr = ctr + 1 8. in ctr 9. Kết thúc
Dhruva Bhagdikar

Tôi có ý nghĩa trong bài viết, bằng cách sử dụng chỉnh sửa, xin lỗi vì sự bất tiện và cảm ơn bạn cho mã giả.
Ác

0

Tôi đã thử dịch sang mã C #, lần đầu tiên chỉ đếm kích thước của mảng tập hợp con và một mảng khác bao gồm toàn bộ tập hợp con (băm).

Đếm:

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;
}

Với tập hợp con:

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
Đây không phải là một trang web mã hóa.
Yuval Filmus

Đây có phải là một trang web toán học?
BigChief

Mức độ chính xác của trang web là khó xác định. Bạn có thể nhìn xung quanh để xem câu hỏi nào bị đóng và câu hỏi nào không.
Yuval Filmus

Mục đích của tôi là thêm một số chiều sâu vào mã đã được đăng, cũng là khối mã sau trả về một tập hợp con tối đa hóa tối đa tập hợp con hoàn toàn thay vì chỉ trả về kích thước của tập hợp con. Hy vọng rằng điều này hữu ích cho bất cứ ai cố gắng hiểu vấn đề trong tay. Ngoài ra tôi hy vọng sẽ nhận được phản hồi về tính chính xác. Đăng mã hay phương trình toán học có tương đương?
BigChief

Mã bài thường được nhăn mặt. Chúng tôi thích mã giả hoặc mô tả văn bản.
Yuval Filmus
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.