ตั้งค่าเลขคณิตเชิงทฤษฎี
หลักฐาน
มีการท้าทายสองสามครั้งแล้วที่เกี่ยวข้องกับการคูณโดยไม่มีตัวดำเนินการคูณ ( ที่นี่และที่นี่ ) และความท้าทายนี้อยู่ในหลอดเลือดดำเดียวกัน (ส่วนใหญ่คล้ายกับลิงก์ที่สอง)
ความท้าทายนี้แตกต่างจากก่อนหน้านี้ที่จะใช้คำจำกัดความทางทฤษฎีชุดของตัวเลขธรรมชาติ ( N ):
และ
ตัวอย่างเช่น,
และอื่น ๆ
ความท้าทาย
เป้าหมายของเราคือการใช้การตั้งค่า (ดูด้านล่าง) เพื่อเพิ่มและคูณจำนวนธรรมชาติ เพื่อจุดประสงค์นี้รายการทั้งหมดจะอยู่ในเดียวกัน 'ชุดภาษาที่มีล่ามอยู่ด้านล่าง สิ่งนี้จะให้ความสม่ำเสมอและการให้คะแนนที่ง่ายขึ้น
ล่ามนี้ช่วยให้คุณสามารถจัดการตัวเลขธรรมชาติเป็นชุด งานของคุณคือการเขียนเนื้อหาของโปรแกรมสองรายการ (ดูด้านล่าง) ซึ่งหนึ่งในนั้นจะเพิ่มจำนวนธรรมชาติอีกตัวหนึ่งจะเพิ่มจำนวนทวีคูณ
หมายเหตุเบื้องต้นเกี่ยวกับชุด
ชุดตามโครงสร้างทางคณิตศาสตร์ปกติ นี่คือบางจุดสำคัญ:
- ไม่มีการสั่งซื้อชุด
- ไม่มีชุดประกอบด้วยตัวเอง
- องค์ประกอบอยู่ในเซตหรือไม่นี่คือบูลีน ดังนั้นองค์ประกอบชุดจึงไม่สามารถมีหลายหลากได้ (เช่นองค์ประกอบไม่สามารถอยู่ในชุดได้หลายครั้ง)
ล่ามและข้อมูลเฉพาะ
'โปรแกรม' สำหรับความท้าทายนี้เขียนขึ้นใน 'set language' และประกอบด้วยสองส่วน: ส่วนหัวและเนื้อหา
หัวข้อ
ส่วนหัวนั้นง่ายมาก มันบอกล่ามว่าคุณกำลังแก้ไขโปรแกรมอะไร ส่วนหัวเป็นบรรทัดเปิดของโปรแกรม มันเริ่มต้นด้วย+
หรือ*
อักขระตามด้วยจำนวนเต็มสองตัวคั่นด้วยช่องว่าง ตัวอย่างเช่น:
+ 3 5
หรือ
* 19 2
เป็นส่วนหัวที่ถูกต้อง ครั้งแรกที่บ่งบอกว่าคุณกำลังพยายามที่จะแก้ปัญหาที่มีความหมายว่าคำตอบของคุณควรจะ3+5
8
ที่สองคล้ายกันยกเว้นการคูณ
ร่างกาย
ร่างกายเป็นที่ที่คำแนะนำที่แท้จริงของคุณในการเป็นล่าม นี่คือสิ่งที่ถือว่าเป็นโปรแกรม "การเพิ่ม" หรือ "การคูณ" ของคุณอย่างแท้จริง คำตอบของคุณจะประกอบด้วยเนื้อหาของโปรแกรมสองรายการหนึ่งรายการสำหรับแต่ละงาน จากนั้นคุณจะเปลี่ยนส่วนหัวเพื่อดำเนินการกรณีทดสอบจริง
ไวยากรณ์และคำแนะนำ
คำสั่งประกอบด้วยคำสั่งตามด้วยพารามิเตอร์ศูนย์หรือมากกว่า สำหรับวัตถุประสงค์ของการสาธิตต่อไปนี้ตัวอักษรใด ๆ ที่เป็นชื่อของตัวแปร จำได้ว่าตัวแปรทั้งหมดมีการตั้งค่า label
เป็นชื่อของป้ายกำกับ (ป้ายกำกับเป็นคำที่ตามด้วยเครื่องหมายอัฒภาค (เช่นmain_loop:
)) int
เป็นจำนวนเต็มต่อไปนี้เป็นคำแนะนำที่ถูกต้อง:
jump label
ข้ามไปที่ฉลากอย่างไม่มีเงื่อนไข ป้ายกำกับคือ 'คำ' ตามด้วยเครื่องหมายอัฒภาค: เช่นmain_loop:
ป้ายกำกับje A label
ข้ามไปที่ป้ายกำกับหาก A ว่างเปล่าjne A label
ข้ามไปที่ป้ายกำกับหาก A ไม่ว่างเปล่าjic A B label
ข้ามไปที่ป้ายกำกับหาก A ประกอบด้วย Bjidc A B label
ข้ามไปที่ป้ายกำกับหาก A ไม่มี B
print A
พิมพ์ค่าจริงของ A โดยที่ {} เป็นชุดว่างprinti variable
พิมพ์การแทนค่าจำนวนเต็มของ A หากมีอยู่มิฉะนั้นเอาต์พุตจะเกิดข้อผิดพลาด
;
เครื่องหมายอัฒภาคบ่งชี้ว่าส่วนที่เหลือของบรรทัดเป็นความคิดเห็นและจะถูกละเว้นโดยล่าม
ข้อมูลเพิ่มเติม
เมื่อเริ่มต้นโปรแกรมมีตัวแปรที่มีอยู่แล้วสามตัว พวกเขามีset1
,set2
ANSWER
และ set1
รับค่าของพารามิเตอร์ส่วนหัวแรก set2
ใช้ค่าของวินาที ANSWER
เป็นชุดเริ่มต้นที่ว่างเปล่า เมื่อโปรแกรมเสร็จสิ้นแล้วล่ามจะตรวจสอบว่าANSWER
เป็นจำนวนเต็มของคำตอบของปัญหาทางคณิตศาสตร์ที่กำหนดไว้ในส่วนหัวหรือไม่ หากเป็นเช่นนั้นจะเป็นการระบุว่ามีข้อความให้ stdout
ล่ามยังแสดงจำนวนการทำงานที่ใช้ ทุกคำสั่งเป็นการทำงานเพียงครั้งเดียว การเริ่มต้นฉลากจะต้องเสียค่าใช้จ่ายในการดำเนินการเพียงครั้งเดียว (สามารถเริ่มป้ายกำกับได้ครั้งเดียวเท่านั้น)
คุณอาจมีตัวแปรสูงสุด 20 ตัว (รวมถึงตัวแปร 3 ตัวที่กำหนดไว้ล่วงหน้า) และ 20 ป้ายกำกับ
รหัสล่าม
หมายเหตุที่สำคัญบนตัวแปลภาษานี้สิ่งต่าง ๆ ช้ามากเมื่อใช้จำนวนมาก (> 30) ในล่ามนี้ ฉันจะร่างเหตุผลสำหรับสิ่งนี้
- โครงสร้างของเซตเป็นเช่นนั้นในการเพิ่มจำนวนธรรมชาติหนึ่งตัวคุณจะเพิ่มขนาดของโครงสร้างเซตได้อย่างมีประสิทธิภาพ n TH จำนวนธรรมชาติมี2 ^ nเซตว่างภายใน (โดยนี้ผมหมายถึงว่าถ้าคุณมองnเหมือนต้นไม้ที่มีnเซตว่าง. หมายเหตุ: เฉพาะเซตว่างสามารถใบ.) ซึ่งหมายความว่าการจัดการกับ 30 อย่างมีนัยสำคัญ ค่าใช้จ่ายสูงกว่าการติดต่อกับ 20 หรือ 10 (คุณกำลังดู 2 ^ 10 กับ 2 ^ 20 เทียบกับ 2 ^ 30)
- การตรวจสอบความเท่าเทียมกันซ้ำ เนื่องจากฉากไม่มีการจัดลำดับที่ถูกกล่าวหานี่จึงเป็นวิธีธรรมชาติในการจัดการกับสิ่งนี้
- มีการรั่วไหลของหน่วยความจำสองแห่งที่ฉันไม่สามารถหาวิธีแก้ไขได้ ฉันไม่ดีที่ C / C ++ ขออภัย เนื่องจากเรากำลังติดต่อกับตัวเลขจำนวนน้อยเท่านั้นและหน่วยความจำที่จัดสรรจะถูกปล่อยให้เป็นอิสระเมื่อสิ้นสุดการทำงานของโปรแกรมนี่จึงไม่น่าเป็นปัญหามากนัก (ก่อนใครบอกว่าใช่ฉันรู้
std::vector
ฉันทำแบบฝึกหัดนี้เพื่อเรียนรู้ถ้าคุณรู้วิธีแก้ไขโปรดแจ้งให้เราทราบและฉันจะแก้ไขไม่เช่นนั้นฉันจะทิ้งมันไว้ อย่างที่เป็น.)
นอกจากนี้สังเกตเห็นเส้นทางรวมถึงset.h
ในinterpreter.cpp
ไฟล์ ไม่มี ado เพิ่มเติมซอร์สโค้ด (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;
}
สภาพการชนะ
คุณอยู่ที่สองเขียนสองโปรแกรมBODIESซึ่งหนึ่งในนั้นคูณตัวเลขในส่วนหัวที่อื่น ๆ ซึ่งจะเพิ่มตัวเลขในส่วนหัว
นี่เป็นรหัสที่ท้าทายที่สุด สิ่งที่เร็วที่สุดจะถูกกำหนดโดยจำนวนของการดำเนินการที่ใช้เพื่อแก้ไขกรณีทดสอบสองกรณีสำหรับแต่ละโปรแกรม กรณีทดสอบคือบรรทัดส่วนหัวต่อไปนี้:
สำหรับนอกจากนี้:
+ 15 12
และ
+ 12 15
และสำหรับการคูณ
* 4 5
และ
* 5 4
คะแนนสำหรับแต่ละกรณีคือจำนวนการปฏิบัติการที่ใช้ (ล่ามจะระบุหมายเลขนี้เมื่อเสร็จสิ้นโปรแกรม) คะแนนรวมคือผลรวมของคะแนนสำหรับแต่ละกรณีทดสอบ
ดูรายการตัวอย่างของฉันสำหรับตัวอย่างของรายการที่ถูกต้อง
ผลงานที่ชนะจะเป็นไปตาม:
- มีสองโปรแกรมเนื้อความหนึ่งซึ่งคูณและหนึ่งซึ่งเพิ่ม
- มีคะแนนรวมต่ำสุด (ผลรวมคะแนนในกรณีทดสอบ)
- ให้เวลาและหน่วยความจำเพียงพอทำงานได้กับจำนวนเต็มใด ๆ ที่ล่ามสามารถจัดการได้ (~ 2 ^ 31)
- แสดงไม่มีข้อผิดพลาดเมื่อทำงาน
- ห้ามใช้คำสั่งการดีบัก
- ไม่ใช้ประโยชน์จากข้อบกพร่องในล่าม ซึ่งหมายความว่าโปรแกรมจริงของคุณควรถูกต้องเป็นรหัสหลอกเช่นเดียวกับโปรแกรมที่แปลได้ใน 'set language'
- ไม่ใช้ช่องโหว่มาตรฐาน (ซึ่งหมายความว่าไม่มีกรณีทดสอบการเข้ารหัส)
โปรดดูตัวอย่างการใช้งานอ้างอิงและตัวอย่างการใช้ภาษา
$$...$$
ใช้ได้กับ Meta แต่ไม่ใช่ใน Main ฉันใช้CodeCogsเพื่อสร้างภาพ