O Fenômeno de Will Rogers

35

O chamado fenômeno de Will Rogers descreve uma maneira de ajustar as estatísticas aumentando a média em dois (multi) conjuntos quando um elemento é movido entre os dois conjuntos. Como um exemplo simples, considere os dois conjuntos

A = {1, 2, 3}
B = {4, 5, 6}

Seus meios aritméticos são 2e 5, respectivamente. Se passarmos 4para A:

A = {1, 2, 3, 4}
B = {5, 6}

Agora, as médias são 2.5e 5.5, respectivamente, portanto, ambas as médias foram aumentadas através de um simples reagrupamento.

Como outro exemplo, considere

A = {3, 4, 5, 6} --> A = {3, 5, 6}
B = {2, 3, 4, 5} --> B = {2, 3, 4, 4, 5}

Por outro lado, não é possível aumentar as duas médias para os conjuntos

A = {1, 5, 9}
B = {4, 5, 7, 8}

O desafio

Dadas duas listas de números inteiros não negativos, determine se é possível aumentar as duas médias movendo um único número inteiro de uma lista para outra.

A média de uma lista vazia não está definida; portanto, se uma das listas contiver apenas um elemento, esse elemento não poderá ser movido.

Você pode escrever um programa ou função, recebendo entrada via STDIN (ou alternativa mais próxima), argumento da linha de comando ou argumento da função e emitindo o resultado via STDOUT (ou alternativa mais próxima), valor de retorno da função ou parâmetro da função (saída).

A entrada pode ser obtida em qualquer formato conveniente de sequência ou lista.

Você não deve assumir que os elementos em cada lista são únicos, nem que são classificados. Você pode assumir que ambas as listas contêm pelo menos um elemento.

A saída deve ser verdadeira se ambas as médias puderem ser aumentadas movendo um único número inteiro e, caso contrário, falsificará .

Isso é código de golfe, então a resposta mais curta (em bytes) vence.

Casos de teste

Verdade:

[1], [2, 3]
[1, 2, 3], [4, 5, 6]
[3, 4, 5, 6], [2, 3, 4, 5]
[6, 5, 9, 5, 6, 0], [6, 2, 0, 9, 5, 2]
[0, 4], [9, 1, 0, 2, 8, 0, 5, 5, 4, 9]

Falsy:

[1], [2]
[2, 4], [5]
[1, 5], [2, 3, 4, 5]
[2, 1, 2, 3, 1, 3], [5, 1, 6]
[4, 4, 5, 2, 4, 0], [9, 2, 10, 1, 9, 0]

Classificação

Aqui está um snippet de pilha para gerar uma classificação regular e uma visão geral dos vencedores por idioma.

Para garantir que sua resposta seja exibida, inicie-a com um título, usando o seguinte modelo de remarcação:

# Language Name, N bytes

onde Nestá o tamanho do seu envio. Se você melhorar sua pontuação, poderá manter as pontuações antigas no título, identificando-as. Por exemplo:

# Ruby, <s>104</s> <s>101</s> 96 bytes

<script>site = 'meta.codegolf'; postID = 5314; isAnswer = true; QUESTION_ID = 53913</script><script src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js'></script><script>jQuery(function(){var u='https://api.stackexchange.com/2.2/';if(isAnswer)u+='answers/'+postID+'?order=asc&sort=creation&site='+site+'&filter=!GeEyUcJFJeRCD';else u+='questions/'+postID+'?order=asc&sort=creation&site='+site+'&filter=!GeEyUcJFJO6t)';jQuery.get(u,function(b){function d(s){return jQuery('<textarea>').html(s).text()};function r(l){return new RegExp('<pre class="snippet-code-'+l+'\\b[^>]*><code>([\\s\\S]*?)</code></pre>')};b=b.items[0].body;var j=r('js').exec(b),c=r('css').exec(b),h=r('html').exec(b);if(c!==null)jQuery('head').append(jQuery('<style>').text(d(c[1])));if (h!==null)jQuery('body').append(d(h[1]));if(j!==null)jQuery('body').append(jQuery('<script>').text(d(j[1])))})})</script>

Martin Ender
fonte
Como matemático e não codificador, não posso realmente enfrentar o desafio, mas estou interessado na seguinte pergunta: Se ambas as médias puderem ser aumentadas deslocando uma coleção finita de números inteiros (digamos cinco) de um conjunto para o outro , segue-se sempre que ambas as médias podem ser aumentadas deslocando apenas um número inteiro ? Mostrando assim que o desafio realmente cobre todos os casos.
Trevor J Richards
3
@TrevorRichards Acho que o último caso de teste falso cobre isso. Você poderia mover um 1e 9mais, o que elevaria ambas as médias, mas você não pode fazê-lo, movendo um único.
Martin Ender
@TrevorRichards Em geral, se os conjuntos A e B têm médias a e b com a <b, ambas as médias podem ser aumentadas se houver um subconjunto C de B com média c tal que a <c <b. Por outro lado, se você exigir que todos os elementos movidos de B para A tenham valores <b, sua hipótese será verdadeira.
Alchymist

Respostas:

11

Pitão, 29 28 26 24 bytes

Obrigado a @Jakube por me salvar 3 bytes com .pe L.

Muito simples, verifica se algum elemento da lista 2 é maior que a média da lista 1 e menor que a média da lista 2 e depois se repete com a lista 1 e a lista 2 alteradas.

Lcsblbff&>YyhT<YyeTeT.pQ

Imprime uma lista não vazia []para truthy e falsey.

L                    Define y(b). Pyth has no builtin for mean
 c                   Float div
  sb                 Sum of b
  lb                 Length of b
f        .pQ         Filter all permutations of input
 f     eT            Filter the last element of the filter var
  &                  Logical and
   >Y                Inner filter var greater than
    y                Call the mean function we defined earlier
     hT              First element of outer filter var
   <Y                Inner filter var less than
    y                Mean of
     eT              Last element of outer filternvar

Experimente online aqui .

Suíte de teste.

Maltysen
fonte
7

Python 3, 74

lambda*L:any(sum(C)/len(C)>x>sum(D)/len(D)for(C,D)in[L,L[::-1]]for x in C)

Toma duas listas como entrada. Verifica se a primeira lista tem um elemento que é maior que a média, mas menor que o da outra. Então, faz o mesmo para as duas entradas trocadas. Ter uma compreensão de lista de duas camadas foi mais curto do que definir uma função separada para tentar as duas ordens (82):

f=lambda A,B:any(sum(A)/len(A)>x>sum(B)/len(B)for x in A)
lambda A,B:f(A,B)|f(B,A)
xnor
fonte
7

Haskell, 58 57

x%y=any(\n->(\g->g x<0&&g y>0)$sum.map(n-))x
x?y=x%y||y%x

podemos verificar se aumentamos ou diminuímos a média, verificando se o elemento a remover ou incluir é maior ou menor que a média.

podemos verificar isso verificando se a média é menor ou maior que um elemento removendo esse elemento da matriz e verificando se a média da nova matriz é negativa ou positiva, o que, por sua vez, é apenas como verificar se a soma é positiva ou negativa .

verificação que é colocada de forma muito simples sum.map(-n+).

orgulhoso haskeller
fonte
6

Mathematica, 49 47 bytes

m=Mean;MemberQ[#2,x_/;m@#<x<m@#2]&@@#~SortBy~m&

Avalia como uma função pura que espera entrada no formulário {list1, list2}.

jcai
fonte
4

APL, 45 40 bytes

Economizou 5 bytes graças a Moris Zucca!

{U←∊⍺⍵[⊃⍒M←(+/÷≢)¨⍺⍵]⋄1∊(U<⌈/M)∧(U>⌊/M)}

Isso cria uma função diádica sem nome que aceita matrizes à esquerda e à direita e retorna 1 ou 0.

{
  M←(+/÷≢)¨⍺⍵          ⍝ Compute the mean of each array
  U←∊⍺⍵[⊃⍒M]           ⍝ Get the array with the larger mean
  1∊(U<⌈/M)∧(U>⌊/M)    ⍝ Any smaller mean < U < larger mean
}

Você pode experimentá-lo online .

Alex A.
fonte
11
você pode escrever a média como: (+ / ÷)
Moris Zucca
@MorisZucca Thanks! Editado para usar sua sugestão.
Alex A.
3

R, 66 52 bytes

Como uma função sem nome, que aceita 2 vetores. Livrei-me de alguns espúrios.

function(a,b)any(a<(m=mean)(a)&a>m(b),b<m(b)&b>m(a))

Testes

> f=
+ function(a,b)any(a<(m=mean)(a)&a>m(b),b<m(b)&b>m(a))
> f(c(1), c(2, 3))
[1] TRUE
> f(c(1, 2, 3), c(4, 5, 6))
[1] TRUE
> f(c(3, 4, 5, 6), c(2, 3, 4, 5))
[1] TRUE
> f(c(6, 5, 9, 5, 6, 0), c(6, 2, 0, 9, 5, 2))
[1] TRUE
> f(c(0, 4), c(9, 1, 0, 2, 8, 0, 5, 5, 4, 9))
[1] TRUE
> 
> f(c(1), c(2))
[1] FALSE
> f(c(2, 4), c(5))
[1] FALSE
> f(c(1, 5), c(2, 3, 4, 5))
[1] FALSE
> f(c(2, 1, 2, 3, 1, 3), c(5, 1, 6))
[1] FALSE
> f(c(4, 4, 5, 2, 4, 0), c(9, 2, 10, 1, 9, 0))
[1] FALSE
> 
MickyT
fonte
3

SAS / IML, 67

start m(a,b);return((a>b[:]&&a<a[:])||(b>a[:]&&b<b[:]))[<>];finish;

Ele usa operadores de redução de índice para obter a resposta, retornando 0 se nenhum elemento for encontrado que corresponda aos requisitos ou 1 se um for encontrado.

Sem jogar golfe, retornarei aqui o valor real usando a multiplicação de matrizes:

proc iml;
  b={1 2 3 4 5 6 7 8 9 };
  a={2 3 4 5 6};
  start m(a,b);
  return (a#(a>b[:] && a < a[:]) || b#(b>a[:] && b < b[:]))[<>];
  finish;

  z= m(a,b);
  print z;
quit;

Testes:

%macro test(a,b,n);
  z&n=m({&a},{&b});
  print z&n;
%mend test;

proc iml;
  b={1 2 3 4 5 };
  a={2 3 4 5 6 7};
start m(a,b);return((a>b[:]&&a<a[:])||(b>a[:]&&b<b[:]))[<>];finish;

* True;
 %test(1,2 3,1);
 %test(1 2 3,4 5 6,2);
 %test(3 4 5 6, 2 3 4 5,3);
 %test(6 5 9 5 6 0,6 2 0 9 5 2,4);
 %test(0 4, 9 1 0 2 8 0 5 5 4 9,5);
* False;
 %test(1,2,6);
 %test(2 4, 5,7);
 %test(1 5, 2 3 4 5,8);
 %test(2 1 2 3 1 3, 5 1 6,9);
 %test(4 4 5 2 4 0, 9 2 10 1 9 0,10);

quit;

(Condensado para facilitar a leitura)

z1 1

z2 1

z3 1

z4 1

z5 1

z6 0

z7 0

z8 0

z9 0

z10 0

Joe
fonte
2

Python 2.7, 102 98 96

lambda p:any([1for i in 0,1for e in p[i]if g[i^1]<e<g[i]]for g in[[sum(l)*1./len(l)for l in p]])

Pega a entrada como matriz das 2 entradas e retorna booleano.
A lógica é -conheça o avg das 2 listas e, em seguida, encontre um elemento que seja menor que o avg de sua própria lista e superior à média da outra lista.

Testá-lo para as entradas fornecidas é demonstrado aqui

Kamehameha
fonte
2
Você pode fazer em *1.vez de *1.0salvar um byte. Como alternativa, se você fizer isso no Python 3, a divisão retornará um float por padrão, portanto você não precisaria dessa multiplicação. (Eu não acho que você teria que alterar o código em que todos possam usar Python 3.)
mathmandan
@mathmandan me salvou um byte. Obrigado :)
Kamehameha
Você pode torná-lo uma função anônima removendo f=e alterando in[0,1]forpara in 0,1for. Já que você está na verdade com 101 bytes, isso o leva a 98.
Kade 28/07
@ Vioz- Obrigado, não sabia que eu poderia fazer isso :)
Kamehameha
2

CJam, 28 bytes

{{_:+1$,d/\+}%$~(m],@0=i)>&}

Essa é uma função anônima que exibe uma matriz bidimensional da pilha e deixa uma matriz de elementos móveis em troca.

Nos navegadores suportados, é possível verificar todos os casos de teste ao mesmo tempo no intérprete CJam .

Casos de teste

Código

q~]{{_:+1$,d/\+}%$~(m],@0=i)>&}%:p

Entrada

[[1] [2 3]]
[[1 2 3] [4 5 6]]
[[3 4 5 6] [2 3 4 5]]
[[6 5 9 5 6 0] [6 2 0 9 5 2]]
[[0 4] [9 1 0 2 8 0 5 5 4 9]]
[[1] [2]]
[[2 4] [5]]
[[1 5] [2 3 4 5]]
[[2 1 2 3 1 3] [5 1 6]]
[[4 4 5 2 4 0] [9 2 10 1 9 0]]

Saída

[2]
[4]
[4]
[5]
[4]
""
""
""
""
""

Como funciona

Se A e B são as matrizes e avg (A) ≤ avg (B) , simplesmente verificamos se B ∩ {⌊ avg (A) ⌋ + 1,…, ⌈ avg (B) ⌉-1} está vazio. Qualquer elemento nessa interseção pode ser movido de B para A para aumentar as duas médias.

{          }%              e# For each of the arrays:
 _:+                       e#   Compute the sum of its elements.
    1$,                    e#   Compute its length.
       d/                  e#   Cast to Double and perform division.
         \+                e#   Prepend the computed average to the array.
             $             e# Sort the arrays (by the averages).
              ~            e# Dump both arrays on the stack.
               (           e# Shift out the higher average.
                m]         e# Round up to the nearest integer b.
                  ,        e# Push [0 ... b-1].
                   @0=     e# Replace the array with lower average by its average.
                      i)   e# Round down to the nearest integer a and add 1.
                        >  e# Skip the first a integer of the range.
                           e# This pushes [a+1 ... b-1].
                         & e# Intersect the result with the remaining array.

Isso empurra a matriz de todos os elementos da matriz com uma média mais alta que pode ser movida para aumentar as duas médias. Essa matriz está vazia / falsa se e somente se nenhum elemento puder ser movido para alcançar esse resultado.

Dennis
fonte
1

Ruby, 86

A=->x{x.reduce(0.0,:+)/x.size}
F=->q{b,a=q.sort_by{|x|A[x]};a.any?{|x|x<A[a]&&x>A[b]}}

Toma como entrada uma matriz contendo as duas matrizes.

Tenta encontrar um item abaixo da média do grupo com a média mais alta que é maior que a média do outro grupo.

Teste: http://ideone.com/444W4U

Cristian Lupascu
fonte
Começou a trabalhar nisso sem perceber que já havia uma solução Ruby, que acabou com algo muito semelhante, mas gera dois caracteres a menos ao fazer com que a função assuma que a primeira lista é 'melhor' e se autodenomina. f=->a,s=1{i,j=a.map{|x|x.inject(0.0,:+)/x.size};a[0].any?{|y|i>y&&j<y}||s&&f[b,a,p]}
Histocrat 27/07/2015
@histocrat Boa abordagem! Eu recebo um NameError sobre a variável bembora. Eu acho que a ligação recursiva deve ser algo como f[a.rotate,p].
Cristian Lupascu
11
Opa, foi assim que obtive uma pontuação melhor trapaceando.
Histocrat
1

Matlab, 54

Usando uma função anônima:

f=@(A,B)any([B>mean(A)&B<mean(B) A>mean(B)&A<mean(A)])

Exemplos:

>> f=@(A,B)any([B>mean(A)&B<mean(B) A>mean(B)&A<mean(A)])
f = 
    @(A,B)any([B>mean(A)&B<mean(B),A>mean(B)&A<mean(A)])

>> f([1 2 3],[4 5 6])
ans =
     1

>> f([3 4 5 6],[2 3 4 5])
ans =
     1

>> f([1 5 9],[4 5 7 8])
ans =
     0
Luis Mendo
fonte
1

C #, 104

bool f(int[]a,int[]b){double i=a.Average(),j=b.Average();return a.Any(x=>x<i&&x>j)||b.Any(x=>x<j&&x>i);}

Chamadas de exemplo:

f(new []{1,2,3}, new []{4,5,6})
f(new []{1}, new []{2, 3})
f(new []{1, 2, 3}, new []{4, 5, 6})
f(new []{3, 4, 5, 6}, new []{2, 3, 4, 5})
f(new []{6, 5, 9, 5, 6, 0}, new []{6, 2, 0, 9, 5, 2})
f(new []{0, 4}, new []{9, 1, 0, 2, 8, 0, 5, 5, 4, 9})

f(new []{1}, new []{2})
f(new []{2, 4}, new []{5})
f(new []{1, 5}, new []{2, 3, 4, 5})
f(new []{2, 1, 2, 3, 1, 3}, new []{5, 1, 6})
f(new []{4, 4, 5, 2, 4, 0}, new []{9, 2, 10, 1, 9, 0})
Stephan Schinkel
fonte
0

C ++ 14, 157 bytes

Como lambda sem nome, retorna pelo último parâmetro r. Assume A, Bpara ser como recipientes vector<int>ou array<int,>.

[](auto A,auto B,int&r){auto m=[](auto C){auto s=0.;for(auto x:C)s+=x;return s/C.size();};r=0;for(auto x:A)r+=x<m(A)&&x>m(B);for(auto x:B)r+=x<m(B)&&x>m(A);}

Ungolfed:

auto f=
[](auto A,auto B,int&r){
  auto m=[](auto C){
   auto s=0.;
   for(auto x:C) s+=x;
   return s/C.size();
  };
  r=0;
  for (auto x:A) r+=x<m(A)&&x>m(B);
  for (auto x:B) r+=x<m(B)&&x>m(A);
}
;

Uso:

int main() {
  std::vector<int>
    a={1,2,3}, b={4,5,6};
  //  a={1,5,9}, b={4,5,7,8};
  int r;
  f(a,b,r);
  std::cout << r << std::endl;
}
Karl Napf
fonte