Sp | Lit wo (r) dS, S (P) aceso wO | rds


15

m | Y bR | ain é Nós | iRd. F (o) RT (h) E La | sT fi (v) e YE | ars O | R s | o, (I) ha | ve C (u) T dois em h (a) lf wh | En (I) s (e) e Th | em. Quando eu comecei a fazê-lo, ele me esforça para me esforçar - B (u) TI quase não pode (N) fazer N (o) T-lo. No entanto, eu o coloquei na parte de trás da minha cabeça, e (n) dificilmente nem o vi. No entanto, pensei que isso seria um grande desafio.

Definições

Para esse desafio, cada letra recebe uma pontuação, com base no meu julgamento de sua largura em uma fonte sem serifa. Você usará essa largura para cortar uma palavra em duas metades da mesma largura. Os caracteres que esse desafio usará são o alfabeto em maiúsculas e minúsculas, apóstrofo e hífen.

Width  Characters
1      i l I '
2      f j r t -
3      a b c d e g h k n o p q s u v x y z
4      m w A B C D E F G H J K L N O P Q R S T U V X Y Z
5      M W

Para minhas explicações e casos de teste, |denota o local em que uma palavra pode ser dividida ao meio.(e) nos dois lados de uma carta, indique que ela será dividida ao meio para criar uma divisão limpa.

Entrada

A entrada consistirá em uma única "palavra" (que não precisa estar no dicionário). Você pode usar esta palavra em qualquer entrada de texto que desejar (String, char array, etc.). Esta palavra conterá apenas letras,, 'e -(veja a tabela acima). Por causa do que você fará com esta palavra (veja abaixo), o caso de entrada é deixado a critério do desenvolvedor. Novas linhas à direita são permitidas, se necessário.

A tarefa

Permute através de todas as formas da entrada (todas as letras em todas as posições possíveis em maiúsculas ou minúsculas). Por exemplo, para entrada it's, a seguir estão todas as permutações:

it's
it'S
iT's
iT'S
It's
It'S
IT's
IT'S

Para dividir uma permutação de uma palavra ao meio, os pontos de um lado da palavra devem ser os mesmos que os do outro lado da palavra. No entanto, se uma carta estiver presa entre duas seções pares, você também poderá cortá-la ao meio.

Observe que "metade" não significa que você se moveu até a metade da string. "Metade" significa que os pontos de ambos os lados são iguais.

Exemplos:

Wé de 5 pontos. ié 1 ponto. Dividir a permutação Wiiiiiao meio resultará em W | iiiii, com 5 pontos em cada lado do |.

Té de 3 pontos. Dividir a permutação TTTTao meio resultará em TT | TT, com 6 pontos em cada lado do| .

wé de 4 pontos. a é 3 pontos. Dividir a permutação wawao meio resultará em w (a) w, com 5,5 pontos em cada lado. Os pontos de asão distribuídos para ambos os lados, comoa é dividido ao meio.

Resultado

Sua saída é um número inteiro do número de permutações exclusivas da entrada que podem ser divididas ao meio de maneira limpa. Novas linhas à direita são permitidas, se necessário.

Casos de teste

Eu emitirei todas as permutações válidas da entrada para os casos de teste. Lembre-se de que isso não faz parte das especificações para você.

Na minha saída intermediária, os números indicam o valor em pontos da letra acima deles, portanto a saída é um pouco mais fácil de visualizar.

Input: a
( a ) 
  3   
( A ) 
  4   
Output: 2

Input: in
Output: 0

Input: ab
A | B 
4   4 
a | b 
3   3 
Output: 2

Input: abc
A ( B ) C 
4   4   4 
A ( b ) C 
4   3   4 
a ( B ) c 
3   4   3 
a ( b ) c 
3   3   3 
Output: 4

Input: will
W ( I ) L l 
5   1   4 1 
W ( I ) l L 
5   1   1 4 
W ( i ) L l 
5   1   4 1 
W ( i ) l L 
5   1   1 4 
w I | L l 
4 1   4 1 
w I | l L 
4 1   1 4 
w i | L l 
4 1   4 1 
w i | l L 
4 1   1 4 
Output: 8

Input: stephen
S T E ( P ) H E N 
4 4 4   4   4 4 4 
S T E ( p ) H E N 
4 4 4   3   4 4 4 
S T E | p h e n 
4 4 4   3 3 3 3 
S T e ( P ) H E n 
4 4 3   4   4 4 3 
S T e ( P ) H e N 
4 4 3   4   4 3 4 
S T e ( P ) h E N 
4 4 3   4   3 4 4 
S T e ( p ) H E n 
4 4 3   3   4 4 3 
S T e ( p ) H e N 
4 4 3   3   4 3 4 
S T e ( p ) h E N 
4 4 3   3   3 4 4 
S t E ( P ) H e n 
4 2 4   4   4 3 3 
S t E ( P ) h E n 
4 2 4   4   3 4 3 
S t E ( P ) h e N 
4 2 4   4   3 3 4 
S t E ( p ) H e n 
4 2 4   3   4 3 3 
S t E ( p ) h E n 
4 2 4   3   3 4 3 
S t E ( p ) h e N 
4 2 4   3   3 3 4 
S t e ( P ) h e n 
4 2 3   4   3 3 3 
S t e p | H E N 
4 2 3 3   4 4 4 
S t e ( p ) h e n 
4 2 3   3   3 3 3 
s T E ( P ) H E n 
3 4 4   4   4 4 3 
s T E ( P ) H e N 
3 4 4   4   4 3 4 
s T E ( P ) h E N 
3 4 4   4   3 4 4 
s T E ( p ) H E n 
3 4 4   3   4 4 3 
s T E ( p ) H e N 
3 4 4   3   4 3 4 
s T E ( p ) h E N 
3 4 4   3   3 4 4 
s T e ( P ) H e n 
3 4 3   4   4 3 3 
s T e ( P ) h E n 
3 4 3   4   3 4 3 
s T e ( P ) h e N 
3 4 3   4   3 3 4 
s T e ( p ) H e n 
3 4 3   3   4 3 3 
s T e ( p ) h E n 
3 4 3   3   3 4 3 
s T e ( p ) h e N 
3 4 3   3   3 3 4 
s t E ( P ) h e n 
3 2 4   4   3 3 3 
s t E p | H E N 
3 2 4 3   4 4 4 
s t E ( p ) h e n 
3 2 4   3   3 3 3 
s t e P | H E N 
3 2 3 4   4 4 4 
s t e p | H E n 
3 2 3 3   4 4 3 
s t e p | H e N 
3 2 3 3   4 3 4 
s t e p | h E N 
3 2 3 3   3 4 4 
Output: 37

Input: splitwords
S P L I T | W O r d s 
4 4 4 1 4   5 4 2 3 3 
<snip>
s p l i t w | o R d S 
3 3 1 1 2 4   3 4 3 4 
Output: 228

Input: 'a-r
' a ( - ) R 
1 3   2   4 
' a | - r 
1 3   2 2 
Output: 2

Input: '''''-
' ' ' ( ' ) ' - 
1 1 1   1   1 2 
Output: 1

Vitória

Isso é , então a resposta mais curta em bytes vence. Você deve poder produzir todos os casos de teste (portanto, todas as entradas com até 10 caracteres) em um período de tempo razoável. Não limite artificialmente sua entrada.

Recompensa

Não sei se isso está no campo da possibilidade. No entanto, você é jogador de golfe - você fará qualquer coisa para o representante. Estou oferecendo uma recompensa de 200 repetições (vou iniciá-la quando essa condição de recompensa for cumprida, como parece basicamente impossível para mim) para um programa que produz a saída correta por antidisestablishmentarianismmenos de 15 segundos em um computador comum (também conhecido como meu). Observe que este caso de teste não deve ser codificado de forma alguma.

@DigitalTrauma esmagou minha recompensa, chegando bem menos de dois segundos. Confira a resposta dele aqui .


2
@MackenzieMcClane, exceto que há cinco 'i' para 2 ^ 23 = 8.388.608.
Jonathan Allan

2
Minha primeira contagem para antidisestablishmentarianism(não-golfy) é 83307040(e corresponde a todos os casos de teste), mas leva ~ 37 segundos no meu laptop (lembre-se de que é Python). Alguém também tem uma conta para isso?
Jonathan Allan

2
43 segundos no TIO
Jonathan Allan

8
Meu cérebro é estranho Você está no lugar certo
Luis Mendo

6
Eu não deveria tentar fazer o mesmo. Eu não tentaria fazer o mesmo. Eu mostrei n (o) tt (r) yt | od | ot (h) e me | O | h cr | ap ...
Arnauld 28/04

Respostas:


8

Pitão , 75 74 73 70 bytes

lfsm} sT-Bysded._Tm.n] d * Fmm? k | qd \ i + 4} d "mw" |} d "il '" h |} d "fjrt -" + 2} d "mw" -2 } d "'- 
lfsm} sT-Bysded._Tm.n] d * Fmm? k | qd \ i + 4} d" mw "| x} Ld + c" mw il' fjrt - ") G1 4-2} d "'- 
lfsm} sT-Bysded._Tm.n] d * Fm <, | x} Ld + c" mw il' fjrt - ") G1 4 | qd \ i + 4} d" mw "-2} d "'-
lfsm} sT-Bysded._Tm.n] d * Fm <, | x} Ld + c "mw il 'fjrt -") G1 4 | qd \ i + 4} d "mw" h} dG

Experimente online!

Pelo amor de Deus, por favor, nem tente antidisestablishmentarianism no intérprete. Você vai travar.

Explicação

lfsm}sT-Bysded._Tm.n]d*Fm<,|x}Ld+c"mw il' fjrt-")G1 4|qd\i+4}d"mw"h}dG

Vamos dividir esse código em X partes.

A primeira parte: gerando versões casadas e mapeando para os valores

m<,|x}Ld+c"mw il' fjrt-")G1 4|qd\i+4}d"mw"h}dG

Sejamos claros aqui. Em nenhuma parte do processo as letras são maiúsculas. Apenas precisamos mapear uma letra para dois valores (e os sinais de pontuação para um valor), sem a necessidade de capitalizá-los. Decidiremos quais caracteres precisaremos de dois valores e para quais caracteres precisaremos de um:

m<,|x}Ld+c"mw il' fjrt-")G1 4|qd\i+4}d"mw"h}dGQ  Q implicitly appended
m                                             Q  for d in Q:
                                           }dG       d in alphabet?
                                          h          +1 (T/F as 1/0)
 <   take the first ^ elements of the following array
     for d in alphabet, it will take 2 elements;
     for d being ' or -, it will take 1 element.
  ,          pair up the following two values
   |x}Ld+c"mw il' fjrt-")G1 4                  this is the first value
                             |qd\i+4}d"mw"    this is the second value

Como você vê, até a primeira parte é muito longa.

O primeiro valor é para a versão em minúscula, que inclui 'e -. O segundo valor é para versão maiúscula, com 'e -não será necessário.

O primeiro valor:

|x}Ld+c"mw il' fjrt-")G1 4
       "mw il' fjrt-"        does what it says on the tin
      c              )       split on spaces, creating an
                             array with three elements
     +                G      append another element, which
                             is the alphabet, as a fail-safe;
                             now the array has 4 elements
  }Ld                        check if d is in each array
                             as with above, True becomes 1
                             and False becomes 0 (T/F as 1/0)
 x                     1     find the first occurrence of 1
|                        4   logical or with 4. If it was 0,
                             it would become 4 now.

A primeira string contém "mw"no índice 0. Tem um valor de 4, o que explica a necessidade do lógico ou. Observe que o Pyth usa a indexação 0. Além disso, o espaço antes do 4é separá-lo de1 .

O segundo valor (maiúsculo):

|qd\i+4}d"mw"
 qd\i          d=="i"
|              logical OR
       }d"mw"  is d in "mw"? That is, is d "m" or "w"?
     +4        +4

Se dfor "i", então ele dá 1o primeiro passo. Caso contrário, continua. Se dfor "m"ou "w", então o terceiro passo dá 1, que é adicionado 4a dar 5. Se dnão é "m"ou "w", então o terceiro passo dá 0, que é adicionado 4a dar 4.

A segunda parte: fazendo o trabalho

lfsm}sT-Bysded._Tm.n]d*F

Isso é anexado à primeira parte, que tecnicamente não é separada da segunda parte (ainda é um comando). Portanto, o valor da primeira parte é passado para a direita.

Recapitulando: na primeira parte, mapeamos as letras para seus valores possíveis (minúsculas e maiúsculas para letras, apenas um valor para os dois sinais de pontuação). Para entrada "ab", seria possível obter[[3,4],[3,4]] .

Para gerar as diferentes versões em caixa (que deveriam ter sido feitas na primeira parte, mas que estourariam), usamos o produto cartesiano repetidamente e depois aplainamos o resultado. Os problemas surgem quando existe apenas uma letra (primeira caixa de teste), porque o produto cartesiano não nos forneceria uma matriz e o comando flatten ( .n) é excedido para fornecer resultados estranhos aos números. Vamos ver como contornei esse problema.

lfsm}sT-Bysded._Tm.n]d*F
                      *F  reduce by Cartesian product
                 m   d    for d in each unflattened version:
                    ]         [d] (wrap in array)
                  .n          flatten
 f                filter for resulting arrays as T
              ._T all prefixes of T
   m              for d in each prefix:
          sd          find the sum of d
         y            double
       -B   ed        [above, above - last element of d]
    }sT               is the sum of T in the above array of 2 elements?
  s               sum the 1/0 generated in each prefix
                  any non-zero value is regarded as truthy
l                 length

Se é uma divisão no meio por | , o prefixo terá a soma dobrada, sendo a soma do total.

Se for dividido por (), a soma do prefixo dobrou menos o valor entre parênteses seria a soma do total.


Sim, quando eu tiver tempo. (Peço desculpas pela minha agenda lotada.)
Freira Furada

11

c, 378 bytes; cerca de 0,6s paraantidisestablishmentarianism

Resposta atualizada . Eu li o comentário de @ JonathanAllan sobrei s, e no começo eu não entendi essa otimização, mas agora vejo que desde tanto ie Iter uma largura de 1, então podemos contar as permutações associadas duas vezes com apenas ter que validar uma vez. Anteriormente, minha solução usava vários threads para espalhar a carga por várias CPUs e com isso eu era capaz de passar por todas as 2 28 possibilidades da minha máquina. Agora com oi otimização, não há necessidade de mexer nos threads - um único thread faz o trabalho facilmente dentro da restrição de tempo.

Sem mais delongas - a função c golfed:

char m[128]={[39]=10,[45]=20};f(s,l,p)char *s;{m[65]?:bcopy("PPPPPPPPPPPdPPPPPPPPPdPPP      <<<<<(<<(<P<<<<(<(<<P<<<",m+65,58);int g,h,u=0,v=0,x=0,y=0,c=0;if(p<l){g=s[p];if(g>64&&g-'i'){s[p]-=32;c+=f(s,l,p+1);}s[p]=g;c+=((g=='i')+1)*f(s,l,p+1);}else{for(l--,p=0,g=m[s[p]],h=m[s[l]];p<=l;){y=v;x=u;if(u+g>v+h){v+=h;h=m[s[--l]];}else{u+=g;g=m[s[++p]];}}c=u==v||y==x;}return c;}

A função recursiva fusa 3 parâmetros - um ponteiro para a sequência de entrada, o comprimento da sequência e o deslocamento na sequência para iniciar o processamento (deve ser 0 para a chamada de nível superior). A função retorna o número de permutações.

Experimente online . Normalmente, o TIO parece ser executado em todos os casos de teste (inclusive antidisestablishmentarianismem menos de 2 segundos.

Observe que existem alguns não imprimíveis na string que é bcopy() editada m[]. O TIO parece lidar com isso corretamente.

Ungolfed:

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>

int width_tbl[] = {
    ['\''] = 1,
    ['-'] = 2,
    ['A'] = 4,4,4,4,4,4,4,4,1,4,4,4,5,4,4,4,4,4,4,4,4,4,5,4,4,4,
    ['a'] = 3,3,3,3,3,2,3,3,1,2,3,1,4,3,3,3,3,2,3,2,3,3,4,3,3,3
};

int
f (char *str, int len, int pos) {
    int lidx, ridx;
    int tot_width = 0;
    int lwidth, rwidth;
    int tot_lwidth = 0, tot_rwidth = 0;
    int prev_tot_lwidth = 0, prev_tot_rwidth = 0;
    char tmp;
    int perm_cnt = 0;

    if (pos < len) {
        tmp = str[pos];
        if (isalpha(tmp) && (tmp != 'i')) {
            str[pos] = toupper(str[pos]);
            perm_cnt += f(str, len, pos+1);
        }
        str[pos] = tmp;
        perm_cnt += ((tmp == 'i') + 1) * f(str, len, pos+1);
    } else {
        //puts(str);
        lidx = 0;
        ridx = len - 1;
        lwidth = width_tbl[str[lidx]];
        rwidth = width_tbl[str[ridx]];
        while (lidx <= ridx) {
            prev_tot_rwidth = tot_rwidth;
            prev_tot_lwidth = tot_lwidth;
            if (tot_lwidth + lwidth > tot_rwidth + rwidth) {
                tot_rwidth += rwidth;
                rwidth = width_tbl[str[--ridx]];
            } else {
                tot_lwidth += lwidth;
                lwidth = width_tbl[str[++lidx]];
            }
        }
        if (tot_lwidth == tot_rwidth) {
            perm_cnt = 1;
        } else if (prev_tot_rwidth == prev_tot_lwidth) {
            perm_cnt = 1;
        }
    }
    return perm_cnt;
}


int main (int argc, char **argv) {
    int i;
    int perm_cnt;

    if (argc > 0) {
        char *str = strdup(argv[1]);
        assert(str);

        perm_cnt = f(str, strlen(str), 0);

        printf("n = %d\n", perm_cnt);
    }

    return 0;
}

Eu tenho um MacBook Pro de meados de 2015 executando o MacOS 10.12.4. O compilador é o clang padrão do MacOS. Estou compilando com:

cc splitwords.c -O2 -o splitwords

A execução de todos os casos de teste, incluindo antidisestablishmentarianism:

$ time ./splitwords
Testcase "a": n = 2
Testcase "in": n = 0
Testcase "ab": n = 2
Testcase "abc": n = 4
Testcase "will": n = 8
Testcase "stephen": n = 37
Testcase "splitwords": n = 228
Testcase "'a-r": n = 2
Testcase "'''''-": n = 1
Testcase "antidisestablishmentarianism": n = 83307040

real    0m0.573s
user    0m0.564s
sys 0m0.003s
$

Isto não é de forma alguma o ideal. O algoritmo simplesmente abre caminho através de todas as possibilidades (módulo i- veja os comentários acima) e conta as palavras que podem ser divididas de acordo com os critérios.


Bom trabalho, realmente acho que provavelmente é possível avaliar o resultado em O (n), usando os efeitos fixos das 7 classes de letra, i , -, ', l, mw, fjrt, e abcdeghknopqsuvxyz, mas que seria necessário um pedido do Pólya enumeração teorema (ou um método de enumeração combinatória equivalente), no qual não sou bem versado.
Jonathan Allan

Você destruiu minhas expectativas, como eu esperava. Esta é a forma como você usa recursão :)
Stephen

1

JavaScript (ES6), 199 169 167 bytes

Espera a sequência de entrada em minúsculas. Muito lento para a recompensa.

f=(s,r=[],t=R=0,i=3,x=parseInt("k1048cccctt"["i'l-fjrtmw".search(c=s[0])+1],36)+8>>i&7)=>x&&(c?(i&&f(s,r,t,0),f(s.slice(1),[x,...r],t+x)):R+=r.some(x=>t==x|!(t-=2*x)))

Casos de teste


1

C, 403 394 bytes,

Obrigado Kevin!

r;char*g[]={"","ilI'","fjrt-","","mw","MW",0},**p,b[99];q(c){for(p=g;*p;p++)if(strchr(*p,c))return p-g;return c>='a'&&c<='z'?3:4;}f(char*w,int l){int i,n,c,t,x,y;if(*w){for(i=0;i<2;i++)x=tolower(*w),y=toupper(*w),!i||x!=y?b[l]=i%2?x:y,b[l+1]=0,f(w+1,l+1):0;}else{t=0;for(c=0;c<2;c++)for(i=0;i<l;i++){x=y=0;for(n=0;n<l;n++)c==0||n!=i?((n<i)?(x+=q(b[n])):(y+=q(b[n]))):0;t|=x==y;}r+=t;}return r;}

Experimente online

Código não destruído:

int getwidth(int c)
{
    char **p, *g[] = { "", "ilI'", "fjrt-", "", "mw", "MW", 0};
    for (p=g; *p; p++)
    {
        if (strchr(*p,c))
            return p-g;
    }
    return c >= 'a' && c <= 'z' ? 3 : 4;
}

int test(char* w, int l)
{
    int i, n, c, t, x, y;

    if (*w)
    {
        for (i=0;i<2; i++)
        {
            x = tolower(*w);
            y = toupper(*w);
            if (!i || x != y)
            {
                b[l] = i % 2 ? x : y;
                b[l + 1] = 0;
                test(w + 1, l+1);
            }
        }
    }
    else
    {
        t = 0;
        for (c=0; c<2; c++)
        {
            for (i=0; i<l; i++)
            {
                x = 0;
                y = 0;
                for (n=0; n<l; n++)
                {
                    if (c == 0 || n != i)
                    {
                        if (n < i)
                            x += getwidth(b[n]);
                        else
                            y += getwidth(b[n]);
                    }
                }
                t |= x == y;
            }
        }
        r += t;
    }
    return r;
}

Você esqueceu de jogar golfe em alguns espaços aqui: f(char* w, int l){->f(char*w,int l){
Kevin Cruijssen
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.