Đặt số học lý thuyết
Tiền đề
Đã có một vài thử thách liên quan đến nhân mà không cần toán tử nhân ( ở đây và ở đây ) và thử thách này nằm trong cùng một hướng (tương tự như liên kết thứ hai).
Thách thức này, không giống như những thách thức trước, sẽ sử dụng một định nghĩa lý thuyết tập hợp về các số tự nhiên ( N ):
và
ví dụ,
và như thế.
Các thách thức
Mục tiêu của chúng tôi là sử dụng các thao tác thiết lập (xem bên dưới), để thêm và nhân các số tự nhiên. Với mục đích này, tất cả các mục sẽ ở cùng một 'ngôn ngữ được đặt' có trình thông dịch bên dưới . Điều này sẽ cung cấp sự nhất quán cũng như ghi điểm dễ dàng hơn.
Trình thông dịch này cho phép bạn thao tác các số tự nhiên dưới dạng tập hợp. Nhiệm vụ của bạn sẽ là viết hai phần thân chương trình (xem bên dưới), một trong số đó thêm các số tự nhiên, phần còn lại nhân chúng.
Ghi chú sơ bộ về bộ
Bộ theo cấu trúc toán học thông thường. Dưới đây là một số điểm quan trọng:
- Bộ không được đặt hàng.
- Không có bộ nào chứa chính nó
- Các phần tử có trong một tập hợp hoặc không, đây là boolean. Do đó, các phần tử tập hợp không thể có bội số (tức là một phần tử không thể nằm trong một tập hợp nhiều lần.)
Thông dịch viên và chi tiết cụ thể
Một 'chương trình' cho thử thách này được viết bằng 'ngôn ngữ tập hợp' và bao gồm hai phần: phần đầu và phần thân.
Tiêu đề
Tiêu đề rất đơn giản. Nó cho người phiên dịch biết bạn đang giải quyết chương trình nào. Tiêu đề là dòng mở đầu của chương trình. Nó bắt đầu bằng +
hoặc *
ký tự, theo sau là hai số nguyên, phân cách bằng dấu cách. Ví dụ:
+ 3 5
hoặc là
* 19 2
là các tiêu đề hợp lệ. Đầu tiên chỉ ra rằng bạn đang cố gắng giải quyết 3+5
, có nghĩa là câu trả lời của bạn nên được 8
. Thứ hai là tương tự ngoại trừ với phép nhân.
Thân hình
Cơ thể là nơi hướng dẫn thực tế của bạn cho thông dịch viên. Đây là những gì thực sự cấu thành chương trình "cộng" hoặc "nhân" của bạn. Câu trả lời của bạn sẽ bao gồm hai cơ quan chương trình, một cho mỗi nhiệm vụ. Sau đó, bạn sẽ thay đổi các tiêu đề để thực sự thực hiện các trường hợp thử nghiệm.
Cú pháp và Hướng dẫn
Các lệnh bao gồm một lệnh theo sau là 0 hoặc nhiều tham số. Đối với các mục đích của các trình diễn sau đây, bất kỳ ký tự bảng chữ cái là tên của một biến. Nhớ lại rằng tất cả các biến là tập hợp. label
là tên của một nhãn (nhãn là các từ được theo sau bởi dấu chấm phẩy (nghĩa là main_loop:
), int
là một số nguyên. Sau đây là các hướng dẫn hợp lệ:
jump label
nhảy vô điều kiện đến nhãn. Nhãn là một "từ" theo sau là dấu chấm phẩy: vdmain_loop:
là nhãn.je A label
nhảy đến nhãn nếu A trốngjne A label
nhảy đến nhãn nếu A không trốngjic A B label
nhảy đến nhãn nếu A chứa Bjidc A B label
nhảy đến nhãn nếu A không chứa B
print A
in giá trị thực của A, trong đó {} là tập hợp trốngprinti variable
in đại diện số nguyên của A, nếu nó tồn tại, nếu không thì xuất ra lỗi.
;
Dấu chấm phẩy chỉ ra rằng phần còn lại của dòng là một nhận xét và sẽ bị người phiên dịch bỏ qua
Thêm thông tin
Khi bắt đầu chương trình, có ba biến trước đó. Họ là set1
,set2
và ANSWER
. set1
lấy giá trị của tham số tiêu đề đầu tiên. set2
lấy giá trị của cái thứ hai. ANSWER
ban đầu là tập rỗng. Sau khi hoàn thành chương trình, trình thông dịch sẽ kiểm tra xem ANSWER
có phải là biểu diễn số nguyên của câu trả lời cho vấn đề số học được xác định trong tiêu đề hay không. Nếu có, nó chỉ ra điều này với một thông báo tới thiết bị xuất chuẩn.
Trình thông dịch cũng hiển thị số lượng các hoạt động được sử dụng. Mỗi hướng dẫn là một thao tác. Bắt đầu một nhãn cũng tốn một thao tác (Nhãn chỉ có thể được bắt đầu một lần).
Bạn có thể có tối đa 20 biến (bao gồm 3 biến được xác định trước) và 20 nhãn.
Mã thông dịch viên
THÔNG BÁO QUAN TRỌNG TRÊN INTERPRETER NÀYMọi thứ rất chậm khi sử dụng số lượng lớn (> 30) trong trình thông dịch này. Tôi sẽ phác thảo những lý do cho việc này.
- Các cấu trúc của các tập hợp sao cho tăng thêm một số tự nhiên, bạn có hiệu quả gấp đôi kích thước của cấu trúc tập hợp. Số tự nhiên thứ n có 2 ^ n tập hợp trống trong đó (ý tôi là nếu bạn nhìn n như một cái cây, có n tập hợp trống. Lưu ý chỉ các tập hợp trống có thể là lá.) Điều này có nghĩa là xử lý 30 là đáng kể tốn kém hơn so với giao dịch với 20 hoặc 10 (bạn đang xem 2 ^ 10 so với 2 ^ 20 so với 2 ^ 30).
- Kiểm tra bình đẳng là đệ quy. Vì các bộ được cho là không có thứ tự, đây dường như là cách tự nhiên để giải quyết vấn đề này.
- Có hai rò rỉ bộ nhớ mà tôi không thể tìm ra cách khắc phục. Tôi rất tệ ở C / C ++, xin lỗi. Vì chúng tôi chỉ xử lý số lượng nhỏ và bộ nhớ được phân bổ sẽ được giải phóng vào cuối chương trình, nên điều này thực sự không phải là vấn đề. (Trước khi bất cứ ai nói bất cứ điều gì, vâng tôi biết
std::vector
; Tôi đã làm điều này như một bài tập học tập. Nếu bạn biết cách khắc phục nó, xin vui lòng cho tôi biết và tôi sẽ thực hiện các chỉnh sửa, nếu không, vì nó hoạt động, tôi sẽ rời khỏi nó như là.)
Ngoài ra, chú ý đường dẫn bao gồm set.h
trong interpreter.cpp
tệp. Nếu không có thêm rắc rối, mã nguồn (C ++):
đặt.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;
thông dịch viên
#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;
}
Điều kiện chiến thắng
Bạn đang hai ghi hai chương trình CƠ QUAN , một trong số đó nhân lên những con số trong các tiêu đề, người kia trong đó bổ sung thêm những con số trong tiêu đề.
Đây là một thách thức mã nhanh nhất . Cái gì nhanh nhất sẽ được xác định bởi số lượng thao tác được sử dụng để giải quyết hai trường hợp thử nghiệm cho mỗi chương trình. Các trường hợp thử nghiệm là các dòng tiêu đề sau:
Ngoài ra:
+ 15 12
và
+ 12 15
và để nhân
* 4 5
và
* 5 4
Điểm cho mỗi trường hợp là số lượng thao tác được sử dụng (trình thông dịch sẽ chỉ ra số này khi hoàn thành chương trình). Tổng số điểm là tổng số điểm cho từng trường hợp kiểm tra.
Xem mục ví dụ của tôi để biết ví dụ về mục hợp lệ.
Một bài dự thi đạt được những điều sau:
- chứa hai phần thân chương trình, một phần tử nhân và một phần bổ sung
- có tổng điểm thấp nhất (tổng điểm trong các trường hợp kiểm tra)
- Cho đủ thời gian và bộ nhớ, hoạt động cho bất kỳ số nguyên nào có thể được xử lý bởi trình thông dịch (~ 2 ^ 31)
- Hiển thị không có lỗi khi chạy
- Không sử dụng lệnh gỡ lỗi
- Không khai thác lỗ hổng trong trình thông dịch. Điều này có nghĩa là chương trình thực tế của bạn phải hợp lệ dưới dạng mã giả cũng như chương trình có thể hiểu được bằng 'ngôn ngữ được đặt'.
- Không khai thác các lỗ hổng tiêu chuẩn (điều này có nghĩa là không có trường hợp kiểm tra mã hóa cứng.)
Xin vui lòng xem ví dụ của tôi để thực hiện tham khảo và sử dụng ví dụ của ngôn ngữ.
$$...$$
hoạt động trên Meta, nhưng không phải trên Main. Tôi đã sử dụng CodeCogs để tạo hình ảnh.