将单词分成相等分数的部分


9

假设A = 1,B = 2 ... Z = 26,并且一个单词的值是这些字母值的总和,则可以将某些单词分为两部分,使它们具有相等的值。

例如,“ wordsplit”可以分为两部分:ordsl wpit,因为o + r + d + s + l = w + p + i + t。

这是我的计算机老师给我们的挑战-显然,这是Lionhead Studios的旧挑战。我已经在Python中解决了该问题,并将很快发布我的答案。

挑战:最短的程序,可以列出所有具有相等分数的拆分。请注意,它仅需为每个字母组列出一个字母-例如,ordsl wpit与rdosl wtip相同。按照它们出现的顺序列出它们会更容易。

奖金:

  • 如果您在两个单词都是有效的英语单词(或字母的某种排列形式)上突出显示对,请使用某种单词列表。(这可以通过在每个方法或其他方法旁边放置一个星号来完成,但要明确说明。)
  • 添加用于删除重复项的选项(这不是默认选项。)
  • 支持两个以上的拆分,例如三个,四个甚至n路拆分。

程序必须支持大小写混合输入吗?如果可以的话,是否可以丢弃输出的大小写?
Nemo157

@ Nemo157它可以忽略大小写,而不必在输出中保留它。
Thomas O

只要人类对输出的要求部分是清楚的,程序是否可以输出其他内容?
JB

@JB是的,可以。
Thomas O

好的,那我就改善一下Perl;)谢谢
JB

Answers:


4

Perl中,115 118 123

@_=~/./g;for$i(1..1<<@_){$l=$
r;$i&1<<$_?$l:$r+=64-ord$_[$_
]for 0..$#_;$l-$r||$i&1<<$_&&
print$_[$_]for 0..$#_;say""}

用运行perl -nE '<code goes here>'。“ n”以代码大小计。

重新排列:

@_ = /./g;
for $i (1 .. 1<<@_) {
  $l = $r;
  $i & 1<<$_ ? $l : $r -= 64 - ord $_[$_] for 0 .. $#_;

  $l - $r      ||
  $i & 1<<$_   &&
  print $_[$_]
    for 0 .. $#_;

  say ""
}

带有注释和变量名:

# split a line of input by character
@chars = /./g;

# generate all binary masks of same length
for $mask (1 .. 1<<@_) {

  # start at "zero"
  $left_sum = $right_sum;

  # depending on mask, choose left or right count
  # 1 -> char goes left; 0 -> char goes right
  $mask & 1<<$_ ? $left_sum : $right_sum
    -= 64 - ord $chars[$_]   # add letter value
      for 0 .. $#chars;      # for all bits in mask

  # if left = right
  $left_sum - $right_sum ||

  # if character was counted left (mask[i] = 1)
  $mask & 1<<$_          &&

  # print it
  print $chars[$_]

  # ...iterating on all bits in mask
    for 0 .. $#chars;

  # newline
  say ""
}

使用的一些技巧:

  • 1..1<<@_覆盖与相同的位范围0..(1<<@_)-1,但更短。(请注意,从更远的角度考虑问题,包括多次包含范围边界都不会导致错误的输出)
  • $ left_range和$ right_range不会重置为实际的“ 0”数字零:由于我们最终进行累加和比较,因此,我们需要以相同的值开始。
  • 减法64-ord$_[$_]而不是加法会ord$_[$_]-64赢得一个看不见的字符:由于它以定界符结尾,因此在for不必要的地方留了空格。
  • Perl允许您分配由三元条件运算符确定的变量cond ? var1 : var2 = new_value
  • &&和链接的布尔表达式||用于代替适当的条件。
  • $l-$r 短于 $l!=$r
  • 即使不平衡的分割也会输出换行符。空行是可以的规则!我问!

愿意为不讲线路噪音的我们这些人解释吗?看起来您使用的二进制屏蔽方法与我的类似,我看到64的意思是'@'='A'-1,在那之后我迷路了。
dmckee ---前主持人小猫,

这个编辑更好吗?
JB

真好 我需要考虑利用将每个计数加到左边或右边的总和。应该是显而易见的,但我错过了。
dmckee ---前主持人小猫,

3

J(109)

~.(/:{[)@:{&a.@(96&+)&.>>(>@(=/@:(+/"1&>)&.>)#[),}.@(split~&.>i.@#@>)@<@(96-~a.&i.)"1([{~(i.@!A.i.)@#)1!:1[1

输出为wordsplit

┌──────┬──────
│船长│浸水│
├─────┼─────
│diltw│oprs│
├─────┼─────
│iptw│dlors│
├─────┼─────
│dlors│iptw│
├─────┼─────
│操作│假阳具│
├─────┼─────
│浸水│放水│
└──────┴──────

说明:

  • 1!:1[1:从stdin读一行
  • ([{~(i.@!A.i.)@#):获取所有排列
  • "1:对于每个排列:
  • (96-~a.&i.):获取字母分数
  • }.@(split~&.>i.@#@>)@<:在每个可能的空间分割分数的每个排列,除了第一个和最后一个数字之后
  • >(>@(=/@:(+/"1&>)&.>)#[):查看哪些排列具有匹配的一半,然后选择它们
  • {&a.@(96&+)&.>:将分数重新转换为字母
  • ~.(/:{[):删除琐碎的变体(例如ordsl wpitordsl wpti

您的某些答案是重复的。
DavidC

@DavidCarraher:好吧,要么我是盲人,要么是盲人,我最近的回答也不是。我从来没有刻意抄袭别人的答案,尽管您当然可能是对的,但我有时会在喝醉的时候贴在这里,直到我收到大量的不赞成票时才想起,结果我提交的东西甚至没有接近正确。如果您看到我的举止不当,或者将评论留在我的举止不当之处,那么我将删除所有令人反感的答案;或降低投票率,因为这就是降低投票率的目的。
marinus,

没有轻微的意图。我只是说,例如,您的第一个答案{“ lorw”,“ dipst”}是您最终答案{“ dipst”,“ lorw”}的重复。仅单词的顺序不同。
DavidC

@DavidCarraher:哎呀:PI认为您的意思是我复制了某人的答案...无论如何,这个问题说(如果我没看错的话)是删除重复部分,其中各个部分只是彼此排列,而不能删除零件顺序不同的零件(即,如果{a,bc}已经找到),则将其移除,{a,cb}但不能移除{bc,a}。(当然,如果我确实/曾经/重复过某人的回答,我当然不会感到冒犯,如果有人指出了我会更喜欢的。)
marinus

你似乎是对的。这些说明说可以忽略单词顺序(“注意,它只需要为每个字母组列出一个字母”),但是他们并不需要。这可以为我节省几个字符。谢谢。
DavidC

2

c99-379个必需字符

#include <stdio.h>
#include <string.h>
#include <ctype.h>
int s(char*w,int l,int m){int b,t=0;for(b=0;b<l;++b){t+=(m&1<<b)?toupper(w[b])-64:0;}return t;}
void p(char*w,int l,int m){for(int b=0;b<l;++b){putchar((m&1<<b)?w[b]:32);}}
int main(){char w[99];gets(w);int i,l=strlen(w),m=(1<<l),t=s(w,l,m-1);
for(i=0;i<m;i++){if(s(w,l,i)==t/2){p(w,l,i);putchar(9);p(w,l,~i);putchar(10);}}}

该方法非常明显。有一种功能可以根据掩码对单词求和,也可以根据掩码进行打印。输入来自标准输入。一种奇怪的是,打印例程在掩膜中没有插入字母空格。选项卡用于分隔组。

我不做任何奖励项目,也不容易将其转换为支持它们。

可读和评论:

#include <stdio.h>
#include <string.h>
#include <ctype.h>
int s(char *w, int l, int m){ /* word, length, mask */
  int b,t=0;                  /* bit and total */
  for (b=0; b<l; ++b){        
/*     printf("Summing %d %d %c %d\n",b,m&(1<<b),w[b],toupper(w[b])-'A'-1); */
    t+=(m&1<<b)?toupper(w[b])-64:0; /* Add to toal if masked (A-1 = @ = 64) */
  }
  return t;
}
void p(char *w, int l, int m){
  for (int b=0; b<l; ++b){ 
    putchar((m&1<<b)?w[b]:32);  /* print if masked (space = 32) */
  }
}
int main(){
  char w[99];
  gets(w);
  int i,l=strlen(w),m=(1<<l),t=s(w,l,m-1);
/*   printf("Word is '%s'\n",w); */
/*   printf("...length %d\n",l); */
/*   printf("...mask   0x%x\n",m-1); */
/*   printf("...total  %d\n",t); */
  for (i=0; i<m; i++){
/*     printf("testing with mask 0x%x...\n",i); */
    if (s(w,l,i)==t/2) {p(w,l,i); putchar(9); p(w,l,~i); putchar(10);}
    /* (tab = 9; newline = 10) */
  }
}

验证方式

 $ wc wordsplit_golf.c
  7  24 385 wordsplit_golf.c
 $ gcc -std=c99 wordsplit_golf.c
 $ echo wordsplit | ./a.out
warning: this program uses gets(), which is unsafe.
 or sp          w  d  lit
wor   l            dsp it
 ords l         w    p it
w    p it        ords l  
   dsp it       wor   l  
w  d  lit        or sp   

1

Ruby:125个字符

r=->a{a.reduce(0){|t,c|t+=c.ord-96}}
f=r[w=gets.chomp.chars]
w.size.times{|n|w.combination(n).map{|s|p([s,w-s])if r[s]*2==f}}

样品运行:

bash-4.2$ ruby -e 'r=->a{a.reduce(0){|t,c|t+=c.ord-96}};f=r[w=gets.chomp.chars.to_a];w.size.times{|p|w.combination(p).map{|q|p([q,w-q])if r[q]*2==f}}' <<< 'wordsplit'
[["w", "o", "r", "l"], ["d", "s", "p", "i", "t"]]
[["w", "p", "i", "t"], ["o", "r", "d", "s", "l"]]
[["o", "r", "s", "p"], ["w", "d", "l", "i", "t"]]
[["w", "d", "l", "i", "t"], ["o", "r", "s", "p"]]
[["o", "r", "d", "s", "l"], ["w", "p", "i", "t"]]
[["d", "s", "p", "i", "t"], ["w", "o", "r", "l"]]

1

数学123 111

查找具有单词“ ascii total”的1/2的所有单词子集d。然后找到这些子集的补数。

d =“ WORDSPLIT”

{#, Complement[w, #]}&/@Cases[Subsets@#,x_/;Tr@x==Tr@#/2]&[Sort[ToCharacterCode@d - 64]];
FromCharacterCode[# + 64] & /@ %

{{“ IPTW”,“ DLORS”},{“ LORW”,“ DIPST”},{“ OPRS”,“ DILTW”},{“ DILTW”,“ OPRS”},{“ DIPST”,“ LORW”} ,{“ DLORS”,“ IPTW”}}


1

J,66个字符

使用base2数字的数字选择每个可能的子集。

   f=.3 :'(;~y&-.)"{y#~a#~(=|.)+/"1((+32*0&>)96-~a.i.y)#~a=.#:i.2^#y'
   f 'WordSplit'
┌─────┬─────┐
│Worl │dSpit│
├─────┼─────┤
│Wdlit│orSp │
├─────┼─────┤
│Wpit │ordSl│
├─────┼─────┤
│ordSl│Wpit │
├─────┼─────┤
│orSp │Wdlit│
├─────┼─────┤
│dSpit│Worl │
└─────┴─────┘

0

我的解决方案如下。它的大小几乎是反高尔夫的,但效果很好。它支持n向拆分(尽管对于大约3个以上的拆分,计算时间会变得很长),并且它支持删除重复项。

class WordSplitChecker(object):
    def __init__(self, word, splits=2):
        if len(word) == 0:
            raise ValueError, "word too short!"
        if splits == 0:
            raise ValueError, "splits must be > 1; it is impossible to split a word into zero groups"
        self.word = word
        self.splits = splits

    def solve(self, uniq_solutions=False, progress_notifier=True):
        """To solve this problem, we first need to consider all the possible
        rearrangements of a string into two (or more) groups.

        It turns out that this reduces simply to a base-N counting algorithm,
        each digit coding for which group the letter goes into. Obviously
        the longer the word the more digits needed to count up to, so 
        computation time is very long for larger bases and longer words. It 
        could be sped up by using a precalculated array of numbers in the
        required base, but this requires more memory. (Space-time tradeoff.)

        A progress notifier may be set. If True, the default notifier is used,
        if None, no notifier is used, and if it points to another callable,
        that is used. The callable must take the arguments as (n, count, 
        solutions) where n is the number of iterations, count is the total 
        iteration count and solutions is the length of the solutions list. The
        progress notifier is called at the beginning, on every 1000th iteration, 
        and at the end.

        Returns a list of possible splits. If there are no solutions, returns
        an empty list. Duplicate solutions are removed if the uniq_solutions
        parameter is True."""
        if progress_notifier == True:
           progress_notifier = self.progress 
        solutions = []
        bucket = [0] * len(self.word)
        base_tuple = (self.splits,) * len(self.word)
        # The number of counts we need to do is given by: S^N,
        # where S = number of splits,
        #       N = length of word.
        counts = pow(self.splits, len(self.word))
        # xrange does not create a list in memory, so this will work with very
        # little additional memory.
        for i in xrange(counts):
            groups = self.split_word(self.word, self.splits, bucket)
            group_sums = map(self.score_string, groups)
            if len(set(group_sums)) == 1:
                solutions.append(tuple(groups))
            if callable(progress_notifier) and i % 1000 == 0:
                progress_notifier(i, counts, len(solutions))
            # Increment bucket after doing each group; we want to include the
            # null set (all zeroes.)
            bucket = self.bucket_counter(bucket, base_tuple)
        progress_notifier(i, counts, len(solutions))
        # Now we have computed our results we need to remove the results that
        # are symmetrical if uniq_solutions is True.
        if uniq_solutions:
            uniques = []
            # Sort each of the solutions and turn them into tuples.  Then we can 
            # remove duplicates because they will all be in the same order.
            for sol in solutions:
                uniques.append(tuple(sorted(sol)))
            # Use sets to unique the solutions quickly instead of using our
            # own algorithm.
            uniques = list(set(uniques))
            return sorted(uniques)
        return sorted(solutions)

    def split_word(self, word, splits, bucket):
        """Split the word into groups. The digits in the bucket code for the
        groups in which each character goes in to. For example,

        LIONHEAD with a base of 2 and bucket of 00110100 gives two groups, 
        "LIHAD" and "ONE"."""
        groups = [""] * splits
        for n in range(len(word)):
            groups[bucket[n]] += word[n]
        return groups

    def score_string(self, st):
        """Score and sum the letters in the string, A = 1, B = 2, ... Z = 26."""
        return sum(map(lambda x: ord(x) - 64, st.upper()))

    def bucket_counter(self, bucket, carry):
        """Simple bucket counting. Ex.: When passed a tuple (512, 512, 512)
        and a list [0, 0, 0] it increments each column in the list until
        it overflows, carrying the result over to the next column. This could
        be done with fancy bit shifting, but that wouldn't work with very
        large numbers. This should be fine up to huge numbers. Returns a new
        bucket and assigns the result to the passed list. Similar to most
        counting systems the MSB is on the right, however this is an 
        implementation detail and may change in the future.

        Effectively, for a carry tuple of identical values, this implements a 
        base-N numeral system, where N+1 is the value in the tuple."""
        if len(bucket) != len(carry):
            raise ValueError("bucket and carry lists must be the same size")
        # Increase the last column.
        bucket[-1] += 1 
        # Carry numbers. Carry must be propagated by at least the size of the
        # carry list.
        for i in range(len(carry)):
            for coln, col in enumerate(bucket[:]):
                if col >= carry[coln]:
                    # Reset this column, carry the result over to the next.
                    bucket[coln] = 0
                    bucket[coln - 1] += 1
        return bucket

    def progress(self, n, counts, solutions):
        """Display the progress of the solve operation."""
        print "%d / %d (%.2f%%): %d solutions (non-unique)" % (n + 1, counts, (float(n + 1) / counts) * 100, solutions) 

if __name__ == '__main__':
    word = raw_input('Enter word: ')
    groups = int(raw_input('Enter number of required groups: '))
    unique = raw_input('Unique results only? (enter Y or N): ').upper()
    if unique == 'Y':
        unique = True
    else:
        unique = False
    # Start solving.
    print "Start solving"
    ws = WordSplitChecker(word, groups)
    solutions = ws.solve(unique)
    if len(solutions) == 0:
        print "No solutions could be found."
    for solution in solutions:
        for group in solution:
            print group,
        print

样本输出:

Enter word: wordsplit
Enter number of required groups: 2
Unique results only? (enter Y or N): y
Start solving
1 / 512 (0.20%): 0 solutions (non-unique)
512 / 512 (100.00%): 6 solutions (non-unique)
dspit worl
ordsl wpit
orsp wdlit

1
我认为,为实现原始问题(代码简洁)的目标而进行的零尝试都是有效的题外话。您承认此答案与代码高尔夫无关,因此与其建议将其发布为答案,不如将其发布为其他答案并在该问题的评论中添加指向它的链接。
Jeff Swensen

2
@Sugerman:这是参考实现,而不是试图赢得比赛的尝试。我更喜欢将参考实现作为答案,而不是占用页面顶部的空间,并且我更喜欢在现场进行实作,以消除链接腐烂的风险。
dmckee ---前主持人小猫,

@Sugerman:为什么不提交?总比没有好。可以将其最小化,但是为什么要打扰-我不能真正接受我自己的问题(嗯,可以,但不是出于这个精神。)
Thomas O

因为在它的基础上,这是一个问答网站。不应将不旨在作为答案的内容发布出来。
杰夫·斯文森

1
就像我在第一条评论中所说的那样,我将在对问题的评论中链接到该链接,或者由于您拥有该问题,因此请在其中编辑链接。只要您没有在不考虑所有其他答案(和投票结果)的情况下自动接受自己的答案,那么提交对自己的问题的答案也没有错。
Jeff Swensen

0

卢阿-195

a=io.read"*l"for i=0,2^#a/2-1 do z,l=0,""r=l for j=1,#a do b=math.floor(i/2^j*2)%2 z=(b*2-1)*(a:byte(j)-64)+z if b>0 then r=r..a:sub(j,j)else l=l..a:sub(j,j)end end if z==0 then print(l,r)end end

输入必须大写:

~$ lua wordsplit.lua 
>WORDSPLIT
WDLIT   ORSP
DSPIT   WORL
WPIT    ORDSL

0

Python-127

w=rawinput()
for q in range(2**len(w)/2):
 a=[0]*2;b=['']*2
 for c in w:a[q%2]+=ord(c)-96;b[q%2]+=c;q/=2
 if a[0]==a[1]:print b

这里是一个182字节的n分割版本,没有重复项:

n,w=input()
def b(q):
 a=[0]*n;b=['']*n
 for c in w:a[q%n]+=ord(c)-96;b[q%n]+=c;q/=n
 return a[0]==a[1] and all(b) and frozenset(b)
print set(filter(None,map(b,range(n**len(w)/n))))

输入例如:

3, 'wordsplit'
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.