이론적 산술 설정
전제
곱셈 연산자 ( 여기 및 여기 ) 없이 곱셈을 포함하는 몇 가지 과제가 이미 있었으며이 과제는 같은 맥락에 있습니다 (두 번째 링크와 가장 유사).
이 과제는 이전의 과제와 달리 자연수 ( N )에 대해 정해진 이론적 정의를 사용합니다 .
과
예를 들어
등등.
도전
우리의 목표는 세트 연산 (아래 참조)을 사용하여 자연수를 더하고 곱하는 것입니다. 이를 위해 모든 항목은 통역사가 아래에있는 동일한 '설정 언어'로되어 있습니다 . 이렇게하면 일관성이 있고 점수를 쉽게 얻을 수 있습니다.
이 해석기는 자연수를 세트로 조작 할 수있게합니다. 당신의 임무는 두 개의 프로그램 본문을 작성하는 것입니다 (아래 참조). 하나는 자연수를 더하고 다른 하나는 곱합니다.
세트에 대한 예비 참고 사항
집합은 일반적인 수학적 구조를 따릅니다. 다음은 몇 가지 중요한 사항입니다.
- 세트는 주문되지 않습니다.
- 세트 자체가 포함되어 있지 않습니다
- 요소가 세트에 있는지 여부에 관계없이 부울입니다. 따라서 세트 요소는 다중성을 가질 수 없습니다 (예 : 요소는 여러 번 세트 될 수 없음).
통역사 및 세부 사항
이 과제에 대한 '프로그램'은 '설정 언어'로 작성되며 헤더와 본문의 두 부분으로 구성됩니다.
헤더
헤더는 매우 간단합니다. 통역사에게 어떤 프로그램을 해결하고 있는지 알려줍니다. 헤더는 프로그램의 첫 줄입니다. +
또는 *
문자로 시작하고 그 뒤에 공백으로 구분 된 두 개의 정수가옵니다. 예를 들면 다음과 같습니다.
+ 3 5
또는
* 19 2
유효한 헤더입니다. 첫 번째는 당신이 해결하기 위해 노력하고 있음을 나타냅니다 3+5
당신의 대답은해야한다는 의미 8
. 두 번째는 곱셈을 제외하고 비슷합니다.
신체
신체는 통역사에게 실제로 지시하는 곳입니다. 이것이 바로 "추가"또는 "곱셈"프로그램을 구성하는 것입니다. 귀하의 답변은 각 작업마다 하나씩 두 개의 프로그램 본문으로 구성됩니다. 그런 다음 실제로 테스트 사례를 수행하도록 헤더를 변경합니다.
구문 및 지침
명령은 명령과 0 개 이상의 매개 변수로 구성됩니다. 다음 데모에서는 알파벳 문자는 변수 이름입니다. 모든 변수가 설정되었음을 기억하십시오. label
레이블의 이름입니다 (레이블은 단어 뒤에 세미콜론 (예 :) main_loop:
),int
정수 다음은 유효한 명령입니다. :
jump label
무조건 레이블로 건너 뜁니다. 레이블은 '단어'다음에 세미콜론이옵니다 (예 :main_loop:
레이블).je A label
A가 비어 있으면 레이블로 이동jne A label
A가 비어 있지 않으면 레이블로 이동jic A B label
A에 B가 포함 된 경우 레이블로 이동jidc A B label
A에 B가 포함되어 있지 않으면 레이블로 이동
print A
A의 실제 값을 인쇄합니다. 여기서 {}는 빈 세트입니다.printi variable
존재하는 경우 A의 정수 표현을 인쇄하고, 그렇지 않으면 오류를 출력합니다.
;
세미콜론은 나머지 행이 주석이며 인터프리터에 의해 무시됨을 나타냅니다.
추가 정보
프로그램 시작시 3 개의 기존 변수가 있습니다. 그들은이다 set1
,set2
하고 ANSWER
. set1
첫 번째 헤더 매개 변수의 값을 가져옵니다. set2
두 번째 값을 가져옵니다. ANSWER
처음에는 빈 세트입니다. 프로그램이 완료되면 통역사는ANSWER
헤더에 정의 된 산술 문제에 대한 답변의 정수 표현 . 그렇다면 stdout에 메시지와 함께이를 표시합니다.
인터프리터는 사용 된 작업 수도 표시합니다. 모든 명령은 하나의 작업입니다. 라벨을 시작하면 한 번의 작업이 필요합니다 (라벨은 한 번만 시작할 수 있습니다).
최대 20 개의 변수 (3 개의 사전 정의 된 변수 포함)와 20 개의 레이블이있을 수 있습니다.
통역사 코드
이 통역사에 대한 중요 사항이 인터프리터에서 많은 수 (> 30)를 사용할 때 상황이 매우 느립니다. 이에 대한 이유를 설명하겠습니다.
- 세트의 구조는 하나의 자연수만큼 증가함에 따라 세트 구조의 크기를 효과적으로 두 배로 증가시킵니다. N 번째 자연수가 ^ n은 2를 그 안에 빈 세트 (난 당신이 보면 뜻이에 의해 n 개의 트리로, 거기에 N 빈 세트. 잎 수 있습니다 단지 빈 설정을 참고.)이 방법을 30 다루는 것은 상당히입니다 20 또는 10을 처리하는 것보다 비용이 많이 듭니다 (2 ^ 10 대 2 ^ 20 대 2 ^ 30을보고 있습니다).
- 평등 점검은 재귀 적입니다. 세트는 순서가 정돈되지 않았기 때문에 이것을 다루는 자연스러운 방법 인 것 같습니다.
- 해결 방법을 알 수없는 두 가지 메모리 누수가 있습니다. C / C ++가 나쁘다. 죄송합니다. 우리는 작은 숫자만을 다루고 있으며 할당 된 메모리는 프로그램 끝에서 해제되므로 실제로 그렇게 큰 문제는 아닙니다. (누군가가 아무 말도하기 전에, 나는 알고있다
std::vector
. 나는 이것을 학습 연습으로하고 있었다. 그것을 고치는 방법을 알고 있다면, 알려 주시면 수정하겠습니다. 그대로.)
또한 파일 set.h
에 포함 경로를 확인 interpreter.cpp
하십시오. 더 이상 고민하지 않고 소스 코드 (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;
인터프리터 .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;
}
승리 조건
두 개의 프로그램 BODIES 두 개를 작성합니다 . 하나는 헤더의 숫자를 곱하고 다른 하나는 헤더에 숫자를 추가합니다.
이것은 가장 빠른 코드 도전입니다. 가장 빠른 것은 각 프로그램에 대해 두 가지 테스트 사례를 해결하는 데 사용되는 작업 수에 따라 결정됩니다. 테스트 케이스는 다음 헤더 행입니다.
또한 :
+ 15 12
과
+ 12 15
곱셈
* 4 5
과
* 5 4
각 사례의 점수는 사용 된 작업 수입니다 (통역사는 프로그램 완료시이 수를 나타냅니다). 총점은 각 테스트 사례에 대한 점수의 합계입니다.
유효한 항목의 예는 내 예제 항목을 참조하십시오.
수상작은 다음을 충족합니다.
- 두 개의 프로그램 본문을 포함합니다. 하나는 곱하고 다른 하나는
- 총 점수가 가장 낮습니다 (테스트 사례의 점수 합계)
- 충분한 시간과 메모리가 주어지면 인터프리터가 처리 할 수있는 모든 정수에 대해 작동합니다 (~ 2 ^ 31)
- 실행할 때 오류가 표시되지 않습니다
- 디버깅 명령을 사용하지 않습니다
- 통역사의 결함을 이용하지 않습니다. 이는 실제 프로그램이 의사 코드뿐만 아니라 '설정 언어'의 해석 가능한 프로그램으로 유효해야 함을 의미합니다.
- 표준 허점을 이용하지 않습니다 (하드 코딩 테스트 사례가 없음).
참조 구현 및 언어 사용 예는 내 예를 참조하십시오.
$$...$$
메타에서는 작동하지만 Main에서는 작동하지 않습니다. 내가 사용 CodeCogs을 이미지를 생성 할 수 있습니다.