คุณมีเคล็ดลับทั่วไปอะไรในการเล่นกอล์ฟใน C ++ ฉันกำลังมองหาแนวคิดที่สามารถนำไปใช้กับปัญหารหัสกอล์ฟโดยทั่วไปซึ่งอย่างน้อยค่อนข้างเฉพาะเจาะจงกับ C ++ (เช่น "ลบความคิดเห็น" ไม่ใช่คำตอบ) กรุณาโพสต์หนึ่งเคล็ดลับต่อคำตอบ
คุณมีเคล็ดลับทั่วไปอะไรในการเล่นกอล์ฟใน C ++ ฉันกำลังมองหาแนวคิดที่สามารถนำไปใช้กับปัญหารหัสกอล์ฟโดยทั่วไปซึ่งอย่างน้อยค่อนข้างเฉพาะเจาะจงกับ C ++ (เช่น "ลบความคิดเห็น" ไม่ใช่คำตอบ) กรุณาโพสต์หนึ่งเคล็ดลับต่อคำตอบ
คำตอบ:
ผู้ประกอบการที่มีเงื่อนไข ternary ?:มักจะสามารถใช้เป็นขาตั้งในที่เรียบง่ายif- elseงบที่เงินออมมาก
เป็นค่าพิเศษที่สามารถใช้เพื่อเลือกค่า lvalues แบบอื่นได้
#include <iostream>
#include <cstdlib>
int main(int c, char**v){
int o=0,e=0,u;
while(--c) ((u=atoi(v[c]))%2?o:e)+=u;
std::cout << "Sum of odds " << o <<std::endl
<< "Sum of evens " << e <<std::endl;
}
e oโปรดทราบว่านี่คือสิ่งที่แตกต่างจากวิธีการทำงานของผู้ประกอบการนี้ในคที่เคล็ดลับนี้ไม่ทำงานเพราะมันไม่สามารถ lvalue
std::endlด้วย'\n'ที่บันทึก 5 ตัวอักษร
บางครั้งคุณสามารถบันทึกอักขระสองตัวโดยใช้ความจริงที่ว่าตัวแปรระยะเวลาการจัดเก็บแบบคงที่ (โดยเฉพาะอย่างยิ่งรวมถึงตัวแปรขอบเขตทั่วโลกทั้งหมด) จะเริ่มต้นเป็นศูนย์โดยอัตโนมัติที่จุดเริ่มต้น (แตกต่างจากตัวแปรอัตโนมัติที่คุณไม่รับประกัน ดังนั้นแทนที่จะ
int main()
{
int a=0;
// ...
}
คุณสามารถเขียน
int a;
int main()
{
// ...
}
บางคอมไพเลอร์ (เช่น GCC) สนับสนุนค่าคงที่ตัวอักษรหลาย สิ่งนี้สามารถบันทึกอักขระสองสามตัวเมื่อต้องการค่าจำนวนเต็มขนาดใหญ่ ตัวอย่าง:
int n=' ';
ค่าเป็นการนำไปปฏิบัติโดยเฉพาะ โดยปกติค่าของการ'ab'เป็นหรือ256*'a'+'b' 'a'+256*'b'คุณสามารถระบุอักขระได้สูงสุด 4 ตัวระหว่างเครื่องหมายคำพูด
สิ่งที่ฉันพบว่ามีประโยชน์:
การใช้ประโยชน์จากความจริงที่ว่าค่าที่ไม่เป็นศูนย์ประเมินเป็นtrueนิพจน์บูลีนและx&&yประเมินว่าx*yเมื่อจัดการกับบูลีน
(x!=0 && y!=0)
ประเมินให้
(x*y)
คุณเพียงแค่ต้องระวังกระแสเกินตามที่ระบุไว้ด้านล่าง
x!=0 && y!=0แล้ว แต่เมื่อใช้การคูณคุณต้องระวังด้วยการล้น เมื่อใช้ 32 บิตจำนวนเต็มx y = = 65536 (และอีกหลายชุดอื่น ๆ ของผู้มีอำนาจของทั้งสอง) นอกจากนี้ยังจะให้ผลผลิตx * Y = 0
&&มีพฤติกรรมการลัดวงจรที่*ขาด ตัวอย่างเช่นคุณไม่สามารถแทนที่ด้วยi++!=0&&j++!=0 i++*j++
ใช้ประเภทต่อไปนี้:
u64, s64, u32, s32 (or int)
สำหรับคำ / ประเภทซ้ำ ๆ ให้ใช้#defines:
#define a while
มันคุ้มค่าถ้าคุณใช้whileมากในการแต่งหน้า 10 ตัวอักษรพิเศษ ( ประมาณ 4 )
เมื่อเป็นไปได้ให้เปลี่ยน&&และ||ไปที่&และ|ตามลำดับ
เมื่อใช้ง่าย ๆ ถ้าข้อความ:
if(<condition>)<stuff>;
สามารถเปลี่ยนเป็น:
<condition>?<stuff>:<any single letter variable>;
ซึ่งบันทึกอักขระ
แทนการใช้while(1)ใช้for(;;)บันทึกตัวละครหนึ่งตัว :)
การใช้เครื่องหมายคอมม่าแทนวงเล็บปีกกาเปิดและปิดสามารถบันทึกอักขระได้ไม่กี่ตัวถ้าคุณมีสถานการณ์ที่ประโยคของคุณมีข้อความสั่งมากกว่าหนึ่งข้อความ:
if(c){x=1;cout<<"Hi";y=2;}else{x=2;cout<<"Bye";y=3;}
เมื่อเทียบกับ
if(c)x=1,cout<<"Hi",y=2;else x=2,cout<<"Bye",y=3;###
บันทึกอักขระสองตัวไว้บน IF ธรรมดาหรือทั้งหมดสามตัวสำหรับ IF / ELSE
ในฐานะที่เป็นจุดแยกระหว่าง C และ C ++ ผลลัพธ์ของนิพจน์คอมม่าใน C ++ โดยรวมอาจถูกใช้เป็น lvalue ... FWIW
เนื่องจากองค์ประกอบอาร์เรย์จะถูกเก็บไว้โดยตรงหลังจากอยู่ในหน่วยความจำแทนที่จะเป็นดังนี้:
for(int x = 0; x < 25; x++) {
for(int y = 0; y < 25; y++)
array[x][y] = whatever;
}
คุณสามารถทำสิ่งนี้:
int* pointer = array;
for(int i = 0; i < 25*25; i++, pointer++)
*pointer = whatever;
เห็นได้ชัดว่าไม่มีสิ่งใดที่กล่าวมาข้างต้นสำหรับกอล์ฟที่อ่านง่าย แต่การใช้พอยน์เตอร์อย่างชัดเจนสามารถช่วยคุณประหยัดพื้นที่ได้มาก
for(int* i=array; i<array+25*25; i++)? จากนั้นคุณจะต้องติดตามตัวแปรเดียวเท่านั้น
ค่อนข้างชัดเจน แต่คุณใช้ไลบรารีมาตรฐานจำนวนมากusing namespace std;อาจบันทึกอักขระไม่กี่ตัว
using std::name;อาจจะค่อนข้างสั้นกว่า
std::ห้าครั้งขึ้นไป
มันจะมีประโยชน์ที่จำได้ว่าเป็นเช่นเดียวกับa[i]*(a+i)
แทนที่a[0]ด้วย*aเพื่อการประหยัดอักขระสองตัว นอกจากนี้a[i][0]จะเทียบเท่ากับ*a[i]และหดตัวลงไปa[0][i] i[*a]ดังนั้นหากคุณเข้ารหัส0ดัชนีในอาเรย์ของคุณอย่างหนักอาจเป็นวิธีที่ดีกว่า
แทนการเขียนอำนาจใหญ่ของ 10 ใช้สัญกรณ์อิเล็กทรอนิกส์ ตัวอย่างเช่นมีความยาวมากกว่าa=1000000000 a=1e9นี้สามารถขยายไปยังหมายเลขอื่น ๆ เช่นดีกว่าa=1e9+24a=1000000024
1e9/xไม่ได้เป็นเช่นเดียวกับหรือ1000000000/x int(1e9)/x
คุณสามารถใช้ตัวดำเนินการที่สาม?:โดยไม่มีการแสดงออกใด ๆ ในบล็อกจริง (มันช่วยประหยัดไบต์)
#include <iostream>
int foo()
{
std::cout << "Foo\n";
}
int main()
{
1?foo():0; // if (true) foo()
0?:foo(); // if (!false) foo()
}
นี่เป็นเฉพาะ GCC มันอาจขยายไปถึงคอมไพเลอร์อื่น ๆ
ใน G ++ bits/stdc++.hส่วนหัวที่ประกอบไว้ล่วงหน้าประกอบด้วยส่วนหัวอื่น ๆ ทั้งหมด หากคุณต้องการimport2 แบบที่แตกต่างกันคุณสามารถใช้มันได้
นี่คือส่วนหัวทั้งหมดที่ระบุไว้ในhttp://en.cppreference.com/w/cpp/header :
เรียงตามลำดับความยาวที่เพิ่มขึ้น
บางส่วนยาวกว่าbits/stdc++.hและบางส่วนต้องการการสนับสนุน C ++ 17 TIO G ++ บางคนไม่รองรับบางคน (ด้วยเหตุผลที่ฉันไม่รู้) กรองพวกเขาที่เรามี:
มันอาจเกิดขึ้นได้ว่าบางคนสามารถถูกแทนที่ด้วยคนที่สั้นกว่า เพียงแค่ค้นหาแบบไบนารี่ไม่ว่าจะเป็นสิ่งที่คุณต้องการจะถูกแทนที่ โดยเฉพาะอย่างยิ่ง:
cstdio -> ios (-3 bytes)
algorithm -> regex (-4 bytes)
vector -> queue (-1 byte)
string -> map (-3 bytes)
bitset -> regex (-1 byte)
numeric -> random (-1 byte)
#importแทนที่จะ#includeให้คุณเพิ่มหนึ่งไบต์
นอกจากนี้อักขระเว้นวรรคระหว่าง#importและส่วนหัวไม่จำเป็นต้อง:
#include <map>
// vs
#import<map>
และถ้าคุณต้องการบางอย่างจากstdlibส่วนหัวคุณสามารถนำเข้าส่วนหัวใด ๆ กับคอนเทนเนอร์ STL (ดีกว่าsetหรือmap ) cstdlibแทน
การดำเนินการทางคณิตศาสตร์ใน Booleans:
แม้ว่า
a*=b>0?.5:-.5
ดีกว่า
if(b>0)a*=.5;else a*=-.5;
มันไม่ดีเท่า
a*=(b>0)-.5
นอกจากนี้ยังใช้ #define กับทุกสิ่งที่ใช้บ่อย มันมักจะสั้นกว่าการใช้ฟังก์ชั่นเนื่องจากชื่อประเภทไม่จำเป็น
รวมสิ่งต่าง ๆ ให้มากที่สุด:
a+=a--;
เป็นเช่นเดียวกับ
a=2*a-1;
xเป็น lvalue และx++rvalue พฤติกรรมที่ไม่ได้กำหนดและจุดลำดับ
สำหรับประเภทอื่นที่ไม่ใช่การintใช้มันเป็นอาร์กิวเมนต์ของฟังก์ชันอาจมีราคาแพง อย่างไรก็ตามมีการแนะนำแลมบ์ดาทั่วไป (ใน C ++ 14?) และอนุญาตให้แลมบ์ดาใด ๆ เป็นเทมเพลตซึ่งการใช้autoประเภทอาร์กิวเมนต์สามารถบันทึกเป็นไบต์ได้ เปรียบเทียบ:
double f(double x, double y)
[](auto x, auto y)
แลมบ์ดาทั่วไปยังสะดวกมากสำหรับการยอมรับตัววนซ้ำ - อาจเป็นวิธีที่ดีที่สุดในการยอมรับอินพุตอาเรย์ใน C ++ คือ[](auto a, auto z)ที่ ๆaและzถูกส่งผ่านเป็นbegin()และend()ของอาร์เรย์ / vector / list / etc
ในความพยายามครั้งแรกของฉันที่การตีกอล์ฟสำหรับงาน "ลบหมายเลขถัดไป"ฉันได้เริ่มต้นจากฟังก์ชั่น (58 ไบต์)
int f(int N, int P){int F;for(F=N;P;F-=++N,P--);return F;}
ปลอดภัยแล้ว 5 ไบต์ด้วยการเปลี่ยนเป็นแลมบ์ดาและย้ายการเริ่มต้นออกจากfor(53)
[](int N,int P){int F=N;for(;P;F-=++N,P--);return F;}
และในที่สุดหลังจากเปลี่ยนจากforเป็นwhileฉันได้ 51 ไบต์:
[](int N,int P){int F=N;while(P--)F-=++N;return F;}
รหัสการทดสอบที่ไม่ถูกจับตาดูมีลักษณะดังนี้:
#include <iostream>
int main(void)
{
int N, P;
std::cin >> N >> P;
auto f = [](int N,int P)
{
int F = N;
while (P--)
F -= ++N;
return F;
};
std::cout << f(N, P) << std::endl;
return 0;
}
UPDATE:
จริงๆแล้วforสามารถเข้าถึงความยาวเท่ากับwhile:
[](int N,int P){int F=N;for(;P--;F-=++N);return F;}
ฉันไปงานปาร์ตี้สาย ...
หากคุณต้องการเปลี่ยนนิพจน์เป็น -1 และ 1 แทน 0 และ 1 แทนที่จะเป็น:
int x;
if (a * 10 > 5)
x = 1;
else
x = -1;
ทำเช่นนี้:
int x = (a * 10 > 5) * 2 - 1;
มันสามารถบันทึกบางไบต์ขึ้นอยู่กับการใช้งาน
int x=(a*10>5)*2-1;ทำคุณทำไม่int x=a*10>5?1:-1;ได้ซึ่งจะสั้นกว่า 1 ไบต์?
หากคุณต้องการสลับสองจำนวนเต็ม a และ b
a^=b^=a^=b;
สามารถใช้งานได้ประหยัด 5 ตัวอักษรกว่าวิธีมาตรฐาน
a+=b;
b=a-b;
a-=b;
,tที่ ints ที่สร้างขึ้นก่อนหน้านี้และจากนั้นt=a;a=b;b=t;จะสั้นกว่า 3 ไบต์ไปa+=b;b=a-b;a-=b;แล้ว แต่ถึงกระนั้นคุณa^=b^=a^=b;ก็สั้นกว่านั้นดังนั้น +1 จากฉัน ผมไม่ทราบว่า C ++ แต่มันใช้งานได้จริง ในฐานะที่เป็น Java รหัสนักกอล์ฟที่ฉันเศร้าก็ดูเหมือนจะไม่ทำงานที่นั่น :(
a^=b;b^=a;a^=b;ทำงานได้ดีใน java
a^=b;b^=a;a^=b;ทำงานแน่นอน แต่มีความยาวเกิน+,t t=a;a=b;b=t;ขออภัยที่กล่าวถึง Java เนื่องจากเป็นหัวข้อที่นี่ แต่เคล็ดลับที่ดีสำหรับนักเขียนโค้ด C ++!
หากคุณใช้คอมไพเลอร์ GCC บางครั้งอาจช่วยให้ใช้ฟังก์ชั่นในตัวเช่น__builtin_putsหรือ__builtin_clzหรือตัวอย่างเช่น,
44 ไบต์:
int main(){__builtin_puts("Hello, world!");}`
50 ไบต์:
#import<cstdio>
int main(){puts("Hello, world!");}
หากคุณกำลังทำ C ++ 11 หรือใหม่กว่า (ซึ่งควรเป็นกรณีนี้เสมอ) ใช้autoสำหรับประเภทที่ซับซ้อนถ้าเป็นไปได้
ตัวอย่าง: 54 ไบต์แทน 66
#include<vector>
std::vector<int> f(std::vector<int> l){return l;}
#include<vector>
auto f(std::vector<int> l){return l;}
นอกจากนี้เนื่องจากประสิทธิภาพไม่สำคัญสำหรับความท้าทายบางอย่าง a std::listอาจทำงานได้น้อยกว่าไม่กี่ไบต์:
#include<list>
auto f(std::list<int> l){return l;}
ฟังก์ชั่นในการ<algorithm>มักจะต้องผ่านa.begin(),a.end()ซึ่งเป็นนานจริงๆแทนคุณสามารถใช้&a[0],&*end(a)เพื่อประหยัด 3 ไบต์ถ้าaเป็นหรือvectorstring
sort(a.begin(),a.end());
sort(begin(a),end(a));
sort(&a[0],&*end(a));
อย่าใช้การใช้งานstring("") ""มันช่วยประหยัด 8 ไบต์
"" + 'a'เป็นchar* + charซึ่งเป็นตัวชี้นอกจากนี้ในขณะที่std::string("") + 'a'เป็นstd::string + char- สตริง string()จะทำงาน.