从一组 n 个元素中找到大小为 r 的唯一集合,只有 1 个大小的子集是共同的

Find unqiue sets of size r from a set of n elements with only 1 size subsets in common

从 n 个元素中找到大小为 r 的唯一集合,使得大小大于 1 的子集在同一顺序中不常见。其中 r 小于 n.

对于 n=10 和 r=5,我能够找到 n 个唯一的集合,它们只有大小为 1 的子集是共同的。即 {1,3} 仅在该顺序的第一组中。

1   3   6   0   5
2   4   7   1   6
3   5   8   2   7
4   6   9   3   8
5   7   0   4   9
6   8   1   5   0
7   9   2   6   1
8   0   3   7   2
9   1   4   8   3
0   2   5   9   4

另一个解决方案

1   4   9   6   5
2   5   0   7   6
3   6   1   8   7
4   7   2   9   8
5   8   3   0   9
6   9   4   1   0
7   0   5   2   1
8   1   6   3   2
9   2   7   4   3
0   3   8   5   4

在一个解中似乎只有 n 个这样的集合是可能的。 如何从数学上证明这一点?

存在多少这样的解决方案,找到所有这些解决方案的算法是什么?

能否将此算法和证明扩展为包含大小为 2(或 p,前提是 p 小于 r)的公共子集。

这是一个已知问题并且可以通过编程方式解决吗?

我试图搜索 http://en.wikipedia.org/wiki/Fano_plane 似乎相关,但我不确定。

首先:据我从您的示例和评论中了解到,您指的不是集合(无序)而是列表(有序)。

解决方案中并不总是 n 个大小为 r 的列表。 例如。 n = 3r = 2

1  2
1  3
2  1
2  3
3  1
3  2

这是一个包含 n⋅(n-1) = 3⋅2 = 6 个大小为 r 的列表的解决方案。

您总共有 n⋅(n-1) 对元素。每个 r 元素列表包含 r-1(重叠)对,因此不同 r 元素列表的理论最大值为 n⋅(n-1)/(r-1)

具有 r 个元素列表的最大数量的解决方案数量(短最大解决方案)受 n⋅(n-1)/(r-1) over m (binomial coefficent) 的限制,其中 m是最大解决方案中的列表数。

在示例中,您看到有一个使用所有 6 个可能列表的最大解决方案,因此只有一个最大解决方案。
该示例还表明可以达到理论界限。

如果您为 nr 使用更大的数字,则可能无法达到此限制。

查找所有内容的算法是使用回溯的枚举算法。只需列出所有可能的对并构建列表。如果您只对一个最大解感兴趣,可能存在更智能的算法。

显然,你的两个解法都违反了问题条件,第一个解法在第一行和第六行重复了1和5的序列,第二个解法在第二行和第九行重复了2和7的序列, 但还是很有意思。

我创建了这段代码来实现您正在寻找的算法,希望这不是浪费我的时间。 这足以证明问题可以通过编程方式解决。

该算法包含三个重要的方法。

order_accepted(ArrayList reslist, int c)

搜索到目前为止我们得到的列表,并且 returns 在这些先前生成的列表中的列表(我们正在构建的)的任何元素之后发生 c 时为 false。

buildlist(ArrayList reslist, int siz_r, int[] arr)

要在不违反我们条件的情况下建立列表,当然是用前面的方法来检查了。

lists_start_with(int c, int siz_r, int[] arr)

我们用它来避免丢失以相同数字开头的列表,我们应该这样做,否则我们将不会得到超过一个以任何元素开头的列表(如果存在的话),我们不能得到两个。

build_solution(int[] arr, int siz_r)

您需要此函数为每个输入数字调用前面的方法,以获取所有以它开头的列表并将它们添加到解决方案中。

要获得解决方案,请在 main 方法中设置输入数组 a 和大小 r,如:

ag.build_solution(new int[]{1,2,3,....},r=..);

解决方案:

a={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}, r=17

1   2   3   4   5   6   7   8   9   10   11   12   13   14   15   16   17    
14  13  12  11  10  9   8   7   6   5    4    3    2    1    18   19   20  


 a={1,2,3,4,5}, r=4

 1    2    3    4    
 3    2    1    5    
  
 a={1,2,3,4,5,6,7,8,9}, r=4

 1    2    3    4    
 1    5    6    7    
 2    1    8    9    
 2    7    6    5    
 3    5    8    1    
 3    6    9    2    
 4    5    9    3    
 4    7    8    2    
 7    9    4    1 


 a={1,2,3,4,5,6,7,8,9}, r=3

 1    2    3    
 1    4    5    
 1    6    7    
 1    8    9    
 2    4    1    
 2    5    6    
 2    7    8    
 3    2    9    
 3    4    6    
 3    5    1    
 3    8    7    
 4    7    2    
 4    8    3    
 5    4    9    
 5    7    3    
 5    8    2    
 6    8    1    
 6    9    2    
 7    6    4     
 7    9    1    
 8    6    5     
 9    6    3    
 9    7    5    
 9    8    4 


 a={1,2,3,4,5,6,7,8,9}, r=6

 1    2    3    4    5    6    
 3    2    1    7    8    9    
 5    4    9    8    7    1   

 

代码:

Class算法:

import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    
    public class Alg {
        public static List<Object> solut = new ArrayList();
    
        @SuppressWarnings("rawtypes")
        public boolean order_accepted(ArrayList reslist, int c) {
            boolean result = true;
            if ((solut != null) && (solut.size() > 0)) {
                Iterator iter = solut.iterator();
                // for every list in this solution
                while (iter.hasNext()) {
                    ArrayList temp = (ArrayList) iter.next();
                    if (temp != null && temp.size() > 0)
                        // for every element in our current list
                        for (int el = 0; el < reslist.size(); el++)
                        // for every element in this list of our solution
                            for (int j = 0; j < temp.size(); j++)
                            if (temp.get(j).equals(reslist.get(el))) {
                    // start looking for c in this list of our
                                    // solution
                                for (int k = j; k < temp.size(); k++) {
                            if (temp.get(k).equals(c)) // if you find c
                                // then it
                    // is after; so will not
                                            // be after any more;
                                            // drop c.
                                            return false;
    
                                    }
                                    break;
                                }
    
                }
            }
            return result;
        }
    
        public boolean is_in_list(int c, ArrayList lst) {
            boolean res = false;
            if (lst != null)
                for (int i = 0; i < lst.size(); i++)
                    if ((Integer) lst.get(i) == c) {
                        res = true;
                        break;
                    }
    
            return res;
        }
    
        public ArrayList copylist(ArrayList lst) {
            ArrayList res = null;
            if (lst != null) {
                res = new ArrayList();
                for (int i = 0; i < lst.size(); i++) {
                    res.add(lst.get(i));
                }
            }
            return res;
        }
    
    // we call this method after we set the first element of the list and
    // (recursively),
    // to get the next (r-1) elements from the input array (arr).
        @SuppressWarnings("unchecked")
    public boolean buildlist(ArrayList reslist, int siz_r, int[] arr) {
    boolean full = false;// this variable determine whether we added an
                // element to this reslist or no available
                                    // element found
    
            if (reslist.size() < siz_r) {
                for (int i = 0; i < arr.length; i++) {
    
                    // if arr[i] is not in the current list and,
        // its order (after) every element is accepted (never happened
                    // in the solution).
                    if (!is_in_list(arr[i], reslist)
                            && order_accepted(reslist, arr[i])) {
    
                        
                        reslist.add(arr[i]);
                        if (reslist.size() == siz_r)// list is full
                        {
                            full = true;
                            break;
                        } 
                        else 
                        {
                          
                            //if fill with others is possible
                            ArrayList tmp=copylist(reslist);
                            if(buildlist(tmp,siz_r,arr))
                            {
                                return buildlist(reslist,siz_r,arr);
                            }
                            
                     //else remove this element
                     //and continue searching for others.
                            else
                            {
                                reslist.remove(reslist.size()-1);
                            }
                        }
    
                        
                    }// endif
                }// endfor
                return full;
            } else
                return true;
        }
    
        public void listes_start_with(int c, int siz_r, int[] arr) {
 // Don't start with other numbers when you still have other listes start
            // withe the same number, Example:
            // arr{1,2,3,4,5} r=3 => (1) 2 3; (1) 4 5; 2 4 1; ...
    // Note that only sub set of size One could be repeated in the same
            // order (relatively); ({12}3; {12}4 are wrong listes).
    
 boolean possible = true;// the possibility of finding other listes start
                        // with c by the result of buildlist method.
            while (possible) {
                ArrayList ls = new ArrayList();
                ls.add(c);
    
                if (c == 2) {
                    int x = 0;
                    x += 1;
                }
                if (buildlist(ls, siz_r, arr))
                    solut.add(ls);
                else
                    possible = false;
            }
        }
    
        public void build_solution(int[] arr, int siz_r) {
            for (int i = 0; i < arr.length; i++) {
                listes_start_with(arr[i], siz_r, arr);
    
            }
        }
    
        @SuppressWarnings("rawtypes")
        public void showsolution() {
            for (int i = 0; i < solut.size(); i++) {
                ArrayList temp = (ArrayList) solut.get(i);
                if (temp != null && temp.size() > 0) {
                    for (int j = 0; j < temp.size(); j++) {
                        System.out.print(temp.get(j) + "    ");
                    }
                }
                System.out.println("");
            }
    
        }

        }

主要Class

public class Mclass {
public static void main(String args[])
{
    Alg ag=new Alg();
    ag.build_solution(new int[]{1,2,3,4,5,6,7,8,9},3);
    ag.showsolution();
    }
}

扩展算法以将所有公共子集包含在一个解决方案中,我认为最好为此创建一个单独的子集。

我无法从数学上证明解决方案中可能列表的数量。 甚至解决方案的全部数量,因为我只知道当您对输入数组进行不同排序时,您会得到(在此算法中)不同的解决方案。