Teorik Aritmetiği Ayarlama
Öncül
Zaten çarpma operatörü olmadan ( burada ve burada ) çarpmayı içeren birkaç zorluk vardır ve bu zorluk aynı damardadır (ikinci bağlantıya en çok benzeyen).
Bu meydan okuma, öncekilerden farklı olarak, doğal sayıların ( N ) belirli bir teorik tanımını kullanacaktır :
ve
Örneğin,
ve bunun gibi.
Meydan okuma
Amacımız doğal sayılar eklemek ve çarpmak için set işlemlerini (aşağıya bakınız) kullanmaktır. Bu amaçla, tüm girişler, tercümanı aşağıda bulunan aynı 'ayarlanan dilde' olacaktır . Bu tutarlılık ve daha kolay puanlama sağlayacaktır.
Bu yorumlayıcı, doğal sayıları setler halinde değiştirmenize izin verir. Göreviniz, biri doğal sayılar ekleyen, diğeri bunları çoğaltan iki program gövdesi (aşağıya bakın) yazmak olacaktır.
Setler Üzerine Ön Notlar
Kümeler olağan matematiksel yapıyı takip eder. İşte bazı önemli noktalar:
- Setler sipariş edilmez.
- Hiçbir küme kendini içermez
- Elemanlar ya bir kümede ya da değil, bu boolean. Bu nedenle, ayar öğelerinin çokluğu olamaz (yani, bir öğe kümede birden çok kez olamaz.)
Tercüman ve özellikler
Bu meydan okuma için bir 'program' 'set language' ile yazılır ve iki bölümden oluşur: bir başlık ve bir gövde.
Başlık
Başlık çok basit. Tercümana hangi programı çözdüğünüzü söyler. Üstbilgi, programın açılış çizgisidir. +
Veya *
karakteri ile başlar , ardından boşlukla ayrılmış iki tamsayı gelir. Örneğin:
+ 3 5
veya
* 19 2
geçerli başlıklardır. Birincisi, çözmeye çalıştığınızı gösterir 3+5
, yani cevabınızın olması gerekir 8
. İkincisi çarpma haricinde benzerdir.
Vücut
Beden, tercüman için gerçek talimatlarınızın olduğu yerdir. "Toplama" ya da "çarpma" programınızı gerçekten oluşturan şey budur. Cevabınız, her görev için bir tane olmak üzere iki program gövdesinden oluşacaktır. Daha sonra test senaryolarını gerçekleştirmek için başlıkları değiştireceksiniz.
Sözdizimi ve Talimatlar
Talimatlar, bir komutun ardından sıfır veya daha fazla parametreden oluşur. Aşağıdaki gösterilerin amaçları doğrultusunda, herhangi bir alfabe karakteri bir değişkenin adıdır. Tüm değişkenlerin küme olduğunu hatırlayın. label
bir etiketin adıdır (etiketler kelimeler ve ardından noktalı virgül (örn. main_loop:
), int
bir tamsayıdır.Aşağıdaki geçerli talimatlardır:
jump label
etikete koşulsuz olarak atlamak. Etiket bir 'sözcük'tür, arkasından noktalı virgül gelir: örneğinmain_loop:
bir etikettir.je A label
A boşsa etikete atlajne A label
A boş değilse etikete atlajic A B label
A B içeriyorsa etikete atlajidc A B label
A B içermiyorsa etikete atla
print A
A'nın gerçek değerini yazdırır; burada {} boş kümeprinti variable
A'nın tamsayı temsilini yazdırır, eğer varsa, hata verir.
;
Noktalı virgül, satırın geri kalanının bir yorum olduğunu ve yorumlayıcı tarafından yok sayılacağını belirtir
Daha fazla bilgi
Program başlangıcında önceden var olan üç değişken vardır. Bunlar set1
,set2
ve ANSWER
. set1
ilk başlık parametresinin değerini alır. set2
saniyenin değerini alır. ANSWER
başlangıçta boş kümedir. Program tamamlandıktan sonra yorumlayıcı ANSWER
, başlıkta tanımlanan aritmetik soruna verilen cevabın tamsayı olup olmadığını kontrol eder . Öyleyse, bunu stdout'a bir mesajla gösterir.
Tercüman ayrıca kullanılan işlem sayısını da görüntüler. Her talimat bir işlemdir. Bir etiketin başlatılması da bir işleme mal olur (Etiketler yalnızca bir kez başlatılabilir).
En fazla 20 değişken (önceden tanımlanmış 3 değişken dahil) ve 20 etiketiniz olabilir.
Tercüman kodu
BU YORUMLAYICI İLE İLGİLİ ÖNEMLİ NOTLARBu yorumlayıcıda çok sayıda (> 30) kullanıldığında işler çok yavaş. Bunun nedenlerini anlatacağım.
- Setlerin yapıları öyle ki, bir doğal sayı kadar artarak, set yapısının boyutunu etkili bir şekilde iki katına çıkarırsınız. N inci doğal sayı vardır ^ n 2 içindeki boş kümeler (Ben eğer bakarsanız anlamına bundan n bir ağaç gibi, orada n boş kümeler. Yapraklar olabilir sadece boş kümeler unutmayın.) Bu aracı 30 ile uğraşan anlamlı olduğunu 20 veya 10 ile uğraşmaktan daha maliyetli (2 ^ 10 vs 2 ^ 20 vs 2 ^ 30'a bakıyorsunuz).
- Eşitlik kontrolleri özyinelemelidir. Setlerin sırasız olduğu iddia edildiğinden, bu bununla başa çıkmanın doğal bir yolu gibi görünüyordu.
- Nasıl düzeltebileceğimi bilemediğim iki bellek sızıntısı var. C / C ++ 'da kötüyüm, üzgünüm. Yalnızca küçük sayılarla uğraştığımız ve ayrılan bellek programın sonunda serbest bırakıldığından, bu gerçekten çok fazla bir sorun olmamalı. (Birisi bir şey söylemeden önce, evet biliyorum
std::vector
; bunu bir öğrenme egzersizi olarak yapıyordum. Nasıl düzelteceğinizi biliyorsanız, lütfen bana bildirin ve düzenlemeleri yapacağım, aksi takdirde işe yaradığından, bırakacağım olduğu gibi.)
Ayrıca, yolunu içerir fark set.h
içinde interpreter.cpp
dosyanın. Daha fazla uzatmadan, kaynak kodu (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;
}
Kazanma koşulu
Siz , biri başlıklardaki sayıları çarpan, diğeri sayıları başlıklara ekleyen iki program BODIES yazıyorsunuz .
Bu en hızlı kod gerektiren bir sorundur. En hızlı olanı, her program için iki test vakasını çözmek için kullanılan işlem sayısı ile belirlenecektir. Test senaryoları aşağıdaki başlık satırlarıdır:
Ek olarak:
+ 15 12
ve
+ 12 15
ve çarpma için
* 4 5
ve
* 5 4
Her vaka için bir puan kullanılan işlem sayısıdır (tercüman program tamamlandıktan sonra bu sayıyı gösterecektir). Toplam puan, her test vakası için puanların toplamıdır.
Geçerli bir giriş örneği için örnek girişime bakın.
Kazanan bir başvuru aşağıdakileri yerine getirir:
- biri çoğalan diğeri ekleyen iki program gövdesi içerir
- en düşük toplam puana sahip (test durumlarındaki skorların toplamı)
- Yeterli zaman ve bellek verildiğinde, yorumlayıcı tarafından işlenebilecek herhangi bir tamsayı için çalışır (~ 2 ^ 31)
- Çalışırken hiçbir hata göstermiyor
- Hata ayıklama komutları kullanmaz
- Tercümandaki kusurları kullanmaz. Bu, gerçek programınızın sözde kod olarak ve 'dil ayarlı' bir yorumlanabilir program olarak geçerli olması gerektiği anlamına gelir.
- Standart boşluklardan yararlanmaz (bu, kodlama test durumları olmadığı anlamına gelir.)
Referans uygulaması ve dilin örnek kullanımı için lütfen örneğime bakın.
$$...$$
Meta üzerinde çalışır, ancak Main üzerinde çalışmaz. Görüntüleri oluşturmak için CodeCogs kullandım .