选择代表数字拼图的独特集合

时间:2011-07-14 06:14:46

标签: algorithm puzzle

以下是给定的输入集。

1009 2000
1009 2001
1002 2002
1003 2002 

每行代表一个组,Number代表组中成员的ID。问题是选择重新呈现完整给定集的最小人数。每个组只能选择一名成员。 2元组成员不会重复。但成员可以成为不止一个群体的一部分。

因此,在此示例中,答案为10092002,代表集合。选择1009是因为它代表两个团队,2002的情况也是如此。

我正在寻找可用于解决此问题的算法。

另一个例子:

1009 2000
1009 2001
1002 2002
1003 2002 
1004 2003

答案可以是{ 1009 , 2002, 1004}{ 1009, 2002, 2003}

4 个答案:

答案 0 :(得分:3)

实际上,Sodved给出的例子表明我错了。它不是由边缘覆盖解决的,因为它仍然存在选择实际顶点的问题。

答案 1 :(得分:0)

你留下了一些细节,所以我做了以下假设。如果他们错了,请告诉我。

  • 每行只有两个数字
  • 某些行上首先出现的数字在其他行上也显示为第二行

因此,如果您将每个数字视为图形中的顶点,并将每行输入视为两个顶点之间的边缘,那么您得到的是bipartite graph - 一组“第一个数字”和一组“第二个数字”,以及它们之间的边缘。现在,将图表分解为每个connected components。在每个连接的组件中,您必须选择所有“第一个数字”或所有“第二个数字”。因此,对于每个连接的组件,选择这两个选项中较小的一个是较小的组。

答案 2 :(得分:0)

如果有人有兴趣,这里有一些笨拙无用的perl代码似乎可以解决这个问题。使用大型数据集需要一段时间。我确信事情可以做得更好,特别是他生成索引排列(sequences)。

#!/usr/bin/perl
# http://stackoverflow.com/questions/6689147/

use strict;
use warnings;

# Return array of arrays with every possible sequence of 0..n-1
sub sequences($);
sub sequences($)
{
    my $n = $_[0];
    my @ret;
    if( $n > 0 )
    {
        for( my $i=0; $i<$n; $i++ )
        {
            my @a = sequences( $n-1 );
            foreach my $br (@a)
            {
                my @b = @$br;
                splice( @b, $i, 0, $n-1 );
                push( @ret, \@b );
            }
        }
    }
    else
    {
        @ret = ( [] );
    }
    return @ret;
} # END sequences

# Remove elements from set which are covered by later elements in set
sub stripset($$)
{
    my( $data, $set ) = @_;
    my $strip = 0;
    my %cover;
    for( my $i=0; $i<scalar(@$set); $i++ )
    {
        my $covered;
        for( my $j=scalar(@$set)-1; $j>$i; $j-- )
        {
            if( $data->{$set->[$j]}->{$set->[$i]}
            &&  !$cover{$set->[$i]} )
            {
                $covered = 1;
                $cover{$set->[$j]} = 1;
                last;
            }
        }
        if( $covered )
        {
            $strip = $i+1;
        }
        else
        {
            last;
        }
    }
    if( $strip )
    {
        splice( @$set, 0, $strip );
    }
} # END stripset

# Load input
my %links;
while( my $line = <STDIN> )
{
    if( $line =~ /^\s*(\S+)\s+(\S+)\s*$/ )
    {
        $links{$1}->{$2} = 1;
        $links{$2}->{$1} = 1;
    }
    else
    {
        warn "INVALID INPUT LINE: $line";
    }
}

my @elems = keys(%links);
my @minset = @elems;
foreach my $seq ( sequences( scalar(@elems) ) )
{
    my @set = map( $elems[$_], @$seq );
#print "TEST set: " . join( ' ', @set ) . "\n";
    stripset( \%links, \@set );
#print "STRP set: " . join( ' ', @set ) . "\n";
    if( scalar(@set) < scalar(@minset) )
    {
        @minset = @set;
    }
}
print "Shortest set: " . join( ' ', @minset ) . "\n";

答案 3 :(得分:0)

只是想注意这个要求

  

每个小组只能选择一名成员。

没有多大意义。如果你强制执行,这个简单的问题

1 2
2 3
3 1

没有解决方案。