Establecer aritmética teórica
Premisa
Ya ha habido un par de desafíos que implican la multiplicación sin el operador de multiplicación ( aquí y aquí ) y este desafío está en la misma línea (más similar al segundo enlace).
Este desafío, a diferencia de los anteriores, utilizará una definición teórica establecida de los números naturales ( N ):
y
por ejemplo,
y así.
El reto
Nuestro objetivo es utilizar operaciones de conjuntos (ver abajo), para sumar y multiplicar números naturales. Para este propósito, todas las entradas estarán en el mismo 'idioma establecido' cuyo intérprete está debajo . Esto proporcionará consistencia y una puntuación más fácil.
Este intérprete le permite manipular números naturales como conjuntos. Su tarea será escribir dos cuerpos de programa (ver más abajo), uno de los cuales agrega números naturales y el otro los multiplica.
Notas preliminares sobre conjuntos
Los conjuntos siguen la estructura matemática habitual. Aquí hay algunos puntos importantes:
- Los conjuntos no están ordenados.
- Ningún conjunto se contiene a sí mismo
- Los elementos están en un conjunto o no, esto es booleano. Por lo tanto, los elementos del conjunto no pueden tener multiplicidades (es decir, un elemento no puede estar en un conjunto varias veces).
Intérprete y detalles
Un 'programa' para este desafío está escrito en 'set language' y consta de dos partes: un encabezado y un cuerpo.
Encabezamiento
El encabezado es muy simple. Le dice al intérprete qué programa está resolviendo. El encabezado es la línea de apertura del programa. Comienza con el carácter +
o *
, seguido de dos enteros, delimitados por espacios. Por ejemplo:
+ 3 5
o
* 19 2
Son encabezados válidos. El primero indica que está tratando de resolver 3+5
, lo que significa que su respuesta debería serlo 8
. El segundo es similar, excepto con la multiplicación.
Cuerpo
El cuerpo es donde están sus instrucciones reales para el intérprete. Esto es lo que realmente constituye su programa de "suma" o "multiplicación". Su respuesta consistirá en dos cuerpos de programa, uno para cada tarea. Luego cambiará los encabezados para llevar a cabo los casos de prueba.
Sintaxis e Instrucciones
Las instrucciones consisten en un comando seguido de cero o más parámetros. Para los propósitos de las siguientes demostraciones, cualquier carácter del alfabeto es el nombre de una variable. Recuerde que todas las variables son conjuntos. label
es el nombre de una etiqueta (las etiquetas son palabras seguidas de punto y coma (es decir main_loop:
), int
es un número entero. Las siguientes son las instrucciones válidas:
jump label
saltar incondicionalmente a la etiqueta. Una etiqueta es una 'palabra' seguida de un punto y coma: por ejemplo,main_loop:
es una etiqueta.je A label
saltar a la etiqueta si A está vacíojne A label
saltar a la etiqueta si A no está vacíojic A B label
saltar a la etiqueta si A contiene Bjidc A B label
saltar a la etiqueta si A no contiene B
print A
imprime el verdadero valor de A, donde {} es el conjunto vacíoprinti variable
imprime una representación entera de A, si existe, de lo contrario genera un error.
;
El punto y coma indica que el resto de la línea es un comentario y el intérprete lo ignorará.
Informacion adicional
Al inicio del programa, hay tres variables preexistentes. Ellos son set1
,set2
y ANSWER
. set1
toma el valor del primer parámetro de encabezado. set2
toma el valor del segundo. ANSWER
Inicialmente es el conjunto vacío. Al finalizar el programa, el intérprete verifica si ANSWER
es la representación entera de la respuesta al problema aritmético definido en el encabezado. Si es así, indica esto con un mensaje para stdout.
El intérprete también muestra el número de operaciones utilizadas. Cada instrucción es una operación. Iniciar una etiqueta también cuesta una operación (las etiquetas solo se pueden iniciar una vez).
Puede tener un máximo de 20 variables (incluidas las 3 variables predefinidas) y 20 etiquetas.
Código de intérprete
NOTAS IMPORTANTES SOBRE ESTE INTÉRPRETELas cosas son muy lentas cuando se usan números grandes (> 30) en este intérprete. Voy a describir las razones de esto.
- Las estructuras de los conjuntos son tales que al aumentar en un número natural, efectivamente se duplica el tamaño de la estructura del conjunto. El n º número natural tiene 2 ^ n conjuntos vacíos dentro de ella (por esto quiero decir que si nos fijamos n como un árbol, hay n conjuntos vacíos. Nota únicos conjuntos vacíos pueden ser hojas.) Esto significa que se trata de 30 es significativamente más costoso que lidiar con 20 o 10 (estás viendo 2 ^ 10 vs 2 ^ 20 vs 2 ^ 30).
- Los controles de igualdad son recursivos. Dado que los conjuntos supuestamente no están ordenados, esta parecía la forma natural de abordar esto.
- Hay dos pérdidas de memoria que no pude encontrar cómo solucionar. Soy malo en C / C ++, lo siento. Como solo tratamos con números pequeños y la memoria asignada se libera al final del programa, esto no debería ser un problema. (Antes de que alguien diga nada, sí, lo sé
std::vector
; estaba haciendo esto como un ejercicio de aprendizaje. Si sabe cómo solucionarlo, avíseme y haré las modificaciones, de lo contrario, ya que funciona, lo dejaré como es.)
Además, observe la ruta de inclusión a set.h
en el interpreter.cpp
archivo. Sin más preámbulos, el código fuente (C ++):
set.h
using namespace std;
//MEMORY LEAK IN THE ADD_SELF METHOD
class set {
private:
long m_size;
set* m_elements;
bool m_initialized;
long m_value;
public:
set() {
m_size =0;
m_initialized = false;
m_value=0;
}
~set() {
if(m_initialized) {
//delete[] m_elements;
}
}
void init() {
if(!m_initialized) {
m_elements = new set[0];
m_initialized = true;
}
}
void uninit() {
if(m_initialized) {
//delete[] m_elements;
}
}
long size() {
return m_size;
}
set* elements() {
return m_elements;
}
bool is_empty() {
if(m_size ==0) {return true;}
else {return false;}
}
bool is_eq(set otherset) {
if( (*this).size() != otherset.size() ) {
return false;
}
else if ( (*this).size()==0 && otherset.size()==0 ) {
return true;
}
else {
for(int i=0;i<m_size;i++) {
bool matched = false;
for(int j=0;j<otherset.size();j++) {
matched = (*(m_elements+i)).is_eq( *(otherset.elements()+j) );
if( matched) {
break;
}
}
if(!matched) {
return false;
}
}
return true;
}
}
bool contains(set set1) {
for(int i=0;i<m_size;i++) {
if( (*(m_elements+i)).is_eq(set1) ) {
return true;
}
}
return false;
}
void add(set element) {
(*this).init();
bool alreadythere = false;
for(int i=0;i<m_size;i++) {
if( (*(m_elements+i)).is_eq(element) ) {
alreadythere=true;
}
}
if(!alreadythere) {
set *temp = new set[m_size+1];
for(int i=0; i<m_size; i++) {
*(temp+i)= *(m_elements+i);
}
*(temp+m_size)=element;
m_size++;
delete[] m_elements;
m_elements = new set[m_size];
for(int i=0;i<m_size;i++) {
*(m_elements+i) = *(temp+i);
}
delete[] temp;
}
}
void add_self() {
set temp_set;
for(int i=0;i<m_size;i++) {
temp_set.add( *(m_elements+i) );
}
(*this).add(temp_set);
temp_set.uninit();
}
void remove(set set1) {
(*this).init();
for(int i=0;i<m_size;i++) {
if( (*(m_elements+i)).is_eq(set1) ) {
set* temp = new set[m_size-1];
for(int j=0;j<m_size;j++) {
if(j<i) {
*(temp+j)=*(m_elements+j);
}
else if(j>i) {
*(temp+j-1)=*(m_elements+j);
}
}
delete[] m_elements;
m_size--;
m_elements = new set[m_size];
for(int j=0;j<m_size;j++) {
*(m_elements+j)= *(temp+j);
}
delete[] temp;
break;
}
}
}
void join(set set1) {
for(int i=0;i<set1.size();i++) {
(*this).add( *(set1.elements()+i) );
}
}
void diff(set set1) {
for(int i=0;i<set1.size();i++) {
(*this).remove( *(set1.elements()+i) );
}
}
void intersect(set set1) {
for(int i=0;i<m_size;i++) {
bool keep = false;
for(int j=0;j<set1.size();j++) {
if( (*(m_elements+i)).is_eq( *(set1.elements()+j) ) ) {
keep = true;
break;
}
}
if(!keep) {
(*this).remove( *(m_elements+i) );
}
}
}
void natural(long number) {
//////////////////////////
//MEMORY LEAK?
//delete[] m_elements;
/////////////////////////
m_size = 0;
m_elements = new set[m_size];
for(long i=1;i<=number;i++) {
(*this).add_self();
}
m_value = number;
}
void disp() {
if( m_size==0) {cout<<"{}";}
else {
cout<<"{";
for(int i=0; i<m_size; i++) {
(*(m_elements+i)).disp();
if(i<m_size-1) {cout<<", ";}
//else{cout<<" ";}
}
cout<<"}";
}
}
long value() {
return m_value;
}
};
const set EMPTY_SET;
interpreter.cpp
#include<fstream>
#include<iostream>
#include<string>
#include<assert.h>
#include<cmath>
#include "headers/set.h"
using namespace std;
string labels[20];
int jump_points[20];
int label_index=0;
const int max_var = 20;
set* set_ptrs[max_var];
string set_names[max_var];
long OPERATIONS = 0;
void assign_var(string name, set other_set) {
static int index = 0;
bool exists = false;
int i = 0;
while(i<index) {
if(name==set_names[i]) {
exists = true;
break;
}
i++;
}
if(exists && index<max_var) {
*(set_ptrs[i]) = other_set;
}
else if(!exists && index<max_var) {
set_ptrs[index] = new set;
*(set_ptrs[index]) = other_set;
set_names[index] = name;
index++;
}
}
int getJumpPoint(string str) {
for(int i=0;i<label_index;i++) {
//cout<<labels[i]<<"\n";
if(labels[i]==str) {
//cout<<jump_points[i];
return jump_points[i];
}
}
cerr<<"Invalid Label Name: '"<<str<<"'\n";
//assert(0);
return -1;
}
long strToLong(string str) {
long j=str.size()-1;
long value = 0;
for(long i=0;i<str.size();i++) {
long x = str[i]-48;
assert(x>=0 && x<=9); // Crash if there was a non digit character
value+=x*floor( pow(10,j) );
j--;
}
return value;
}
long getValue(string str) {
for(int i=0;i<max_var;i++) {
if(set_names[i]==str) {
set set1;
set1.natural( (*(set_ptrs[i])).size() );
if( set1.is_eq( *(set_ptrs[i]) ) ) {
return (*(set_ptrs[i])).size();
}
else {
cerr<<"That is not a valid integer construction";
return 0;
}
}
}
return strToLong(str);
}
int main(int argc, char** argv){
if(argc<2){std::cerr<<"No input file given"; return 1;}
ifstream inf(argv[1]);
if(!inf){std::cerr<<"File open failed";return 1;}
assign_var("ANSWER", EMPTY_SET);
int answer;
string str;
inf>>str;
if(str=="*") {
inf>>str;
long a = strToLong(str);
inf>>str;
long b = strToLong(str);
answer = a*b;
set set1; set set2;
set1.natural(a); set2.natural(b);
assign_var("set1", set1);
assign_var("set2",set2);
//cout<<answer;
}
else if(str=="+") {
inf>>str;
long a = strToLong(str);
inf>>str;
long b = strToLong(str);
answer = a+b;
set set1; set set2;
set1.natural(a); set2.natural(b);
assign_var("set1", set1);
assign_var("set2",set2);
//cout<<answer;
}
else{
cerr<<"file must start with '+' or '*'";
return 1;
}
// parse for labels
while(inf) {
if(inf) {
inf>>str;
if(str[str.size()-1]==':') {
str.erase(str.size()-1);
labels[label_index] = str;
jump_points[label_index] = inf.tellg();
//cout<<str<<": "<<jump_points[label_index]<<"\n";
label_index++;
OPERATIONS++;
}
}
}
inf.clear();
inf.seekg(0,ios::beg);
// parse for everything else
while(inf) {
if(inf) {
inf>>str;
if(str==";") {
getline(inf, str,'\n');
}
// jump label
if(str=="jump") {
inf>>str;
inf.seekg( getJumpPoint(str),ios::beg);
OPERATIONS++;
}
// je set label
if(str=="je") {
inf>>str;
for(int i=0;i<max_var;i++) {
if( set_names[i]==str) {
if( (*(set_ptrs[i])).is_eq(EMPTY_SET) ) {
inf>>str;
inf.seekg( getJumpPoint(str),ios::beg);
OPERATIONS++;
}
break;
}
}
}
// jne set label
if(str=="jne") {
inf>>str;
for(int i=0;i<max_var;i++) {
if( set_names[i]==str) {
if(! (*(set_ptrs[i])).is_eq(EMPTY_SET) ) {
inf>>str;
inf.seekg( getJumpPoint(str),ios::beg);
OPERATIONS++;
}
break;
}
}
}
// jic set1 set2 label
// jump if set1 contains set2
if(str=="jic") {
inf>>str;
string str2;
inf>>str2;
set set1;
set set2;
for(int i=0;i<max_var;i++) {
if( set_names[i]==str ) {
set1 = *(set_ptrs[i]);
}
if(set_names[i]==str2) {
set2 = *(set_ptrs[i]);
}
}
if( set1.contains(set2) ) {
inf>>str;
inf.seekg( getJumpPoint(str),ios::beg);
OPERATIONS++;
}
else {inf>>str;}
}
// jidc set1 set2 label
// jump if set1 doesn't contain set2
if(str=="jidc") {
inf>>str;
string str2;
inf>>str2;
set set1;
set set2;
for(int i=0;i<max_var;i++) {
if( set_names[i]==str ) {
set1 = *(set_ptrs[i]);
}
if(set_names[i]==str2) {
set2 = *(set_ptrs[i]);
}
}
if( !set1.contains(set2) ) {
inf>>str;
inf.seekg( getJumpPoint(str),ios::beg);
OPERATIONS++;
}
else {inf>>str;}
}
// assign variable set/int
if(str=="assign") {
inf>>str;
string str2;
inf>>str2;
set set1;
set1.natural( getValue(str2) );
assign_var(str,set1);
OPERATIONS++;
}
// union set1 set2 set3
// set1 = set2 u set3
if(str=="union") {
inf>>str;
int i=0;
while(i<max_var) {
if( set_names[i] == str ) {
break;
}
i++;
}
set set1;
set set2;
string str1;
inf>>str1;
string str2;
inf>>str2;
for(int j=0;j<max_var;j++) {
if( str1 == set_names[j] ) {
set1= *(set_ptrs[j]);
}
if( str2 == set_names[j] ) {
set2= *(set_ptrs[j]);
}
}
set1.join(set2);
if(i==max_var) {
assign_var(str,set1);
}
else {
set_names[i]= str;
set_ptrs[i] = new set;
*(set_ptrs[i]) = set1;
}
OPERATIONS++;
}
// intersect set1 set2 set3
// set1 = set2^set3
if(str == "intersect") {
inf>>str;
int i=0;
while(i<max_var) {
if( set_names[i] == str ) {
break;
}
i++;
}
set set1;
set set2;
string str1;
inf>>str1;
string str2;
inf>>str2;
for(int j=0;j<max_var;j++) {
if( str1 == set_names[j] ) {
set1= *(set_ptrs[j]);
}
if( str2 == set_names[j] ) {
set2= *(set_ptrs[j]);
}
}
set1.intersect(set2);
if(i==max_var) {
assign_var(str,set1);
}
else {
set_names[i]= str;
set_ptrs[i] = new set;
*(set_ptrs[i]) = set1;
}
OPERATIONS++;
}
// difference set1 set2 set3
// set1 = set2\set3
if(str == "difference") {
inf>>str;
int i=0;
while(i<max_var) {
if( set_names[i] == str ) {
break;
}
i++;
}
set set1;
set set2;
string str1;
inf>>str1;
string str2;
inf>>str2;
for(int j=0;j<max_var;j++) {
if( str1 == set_names[j] ) {
set1= *(set_ptrs[j]);
}
if( str2 == set_names[j] ) {
set2= *(set_ptrs[j]);
}
}
set1.diff(set2);
if(i==max_var) {
assign_var(str,set1);
}
else {
set_names[i]= str;
set_ptrs[i] = new set;
*(set_ptrs[i]) = set1;
}
OPERATIONS++;
}
// add set1 set2
// put set2 in set 1
if(str=="add") {
inf>>str;
int i = 0; int j =0;
while(i<max_var) {
if(set_names[i]==str) {
break;
}
i++;
}
inf>>str;
while(j<max_var) {
if(set_names[j]==str) {
break;
}
j++;
}
set set2 = *(set_ptrs[j]);
if( ! (*(set_ptrs[i])).is_eq(set2) ){
(*(set_ptrs[i])).add(set2);
}
else {
(*(set_ptrs[i])).add_self();
}
OPERATIONS++;
}
// remove set1 set2
// remove set2 from set1
if(str=="remove") {
inf>>str;
int i = 0; int j =0;
while(i<max_var) {
if(set_names[i]==str) {
break;
}
i++;
}
inf>>str;
while(j<max_var) {
if(set_names[j]==str) {
break;
}
j++;
}
set set2 = *(set_ptrs[j]);
(*(set_ptrs[i])).remove(set2);
OPERATIONS++;
}
// print set
// prints true representation of set
if(str=="print") {
inf>>str;
for(int i=0;i<max_var;i++) {
if(set_names[i]==str) {
(*(set_ptrs[i])).disp();
}
}
cout<<"\n";
}
// printi set
// prints integer representation of set, if exists.
if(str=="printi") {
inf>>str;
cout<<getValue(str);
cout<<"\n";
}
}
}
cout<<"You used "<<OPERATIONS<<" operations\n";
set testset;
testset.natural(answer);
switch( testset.is_eq( *(set_ptrs[0]) ) ) {
case 1:
cout<<"Your answer is correct, the set 'ANSWER' is equivalent "<<answer<<".\n";
break;
case 0:
cout<<"Your answer is incorrect\n";
}
// cout<<"\n";
return 0;
}
Condición ganadora
Ustedes dos escriben dos CUERPOS del programa , uno de los cuales multiplica los números en los encabezados y el otro agrega los números en los encabezados.
Este es un desafío de código más rápido . Lo más rápido estará determinado por el número de operaciones utilizadas para resolver dos casos de prueba para cada programa. Los casos de prueba son las siguientes líneas de encabezado:
Para la adición:
+ 15 12
y
+ 12 15
y para multiplicar
* 4 5
y
* 5 4
Una puntuación para cada caso es el número de operaciones utilizadas (el intérprete indicará este número al finalizar el programa). El puntaje total es la suma de los puntajes para cada caso de prueba.
Vea mi entrada de ejemplo para ver un ejemplo de una entrada válida.
Una presentación ganadora cumple lo siguiente:
- contiene dos cuerpos de programa, uno que se multiplica y otro que agrega
- tiene el puntaje total más bajo (suma de puntajes en casos de prueba)
- Dado el tiempo y la memoria suficientes, funciona para cualquier número entero que pueda ser manejado por el intérprete (~ 2 ^ 31)
- No muestra errores cuando se ejecuta
- No usa comandos de depuración
- No explota defectos en el intérprete. Esto significa que su programa actual debe ser válido como pseudocódigo y como un programa interpretable en 'set language'.
- No explota las lagunas estándar (esto significa que no hay casos de prueba de codificación fija).
Consulte mi ejemplo para la implementación de referencia y el uso de ejemplo del lenguaje
fuente
$$...$$
funciona en Meta, pero no en Main. Solía CodeCogs para generar las imágenes.Respuestas:
Ejemplo de respuesta, 1323 operaciones
Tenga en cuenta que este es un ejemplo, no una entrada real.
Cuerpo adicional
Tenga en cuenta que este cuerpo no se ejecutará sin un encabezado.
Los comentarios no son necesarios en una respuesta real, pero están ahí para ayudar a enseñar los conceptos básicos del idioma.
Para caso de prueba
usos
440 operations
y para caso de pruebausos
299 operations
.Cuerpo de multiplicación
Para caso de prueba
usos
305 operations
y para caso de pruebausos
279 operations
.Por lo tanto, mi puntaje total es
440+299+305+279 =
1323
fuente
min
ymax
usarlasunion
yintersection
, para que las dos adiciones y las dos multiplicaciones obtengan el mismo puntaje (más bajo). Eso no parece una mejora suficiente para estafar el resto de esta solución de referencia. ;)