คุณมีเคล็ดลับทั่วไปอะไรในการเล่นกอล์ฟใน 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+24
a=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
ส่วนหัวที่ประกอบไว้ล่วงหน้าประกอบด้วยส่วนหัวอื่น ๆ ทั้งหมด หากคุณต้องการimport
2 แบบที่แตกต่างกันคุณสามารถใช้มันได้
นี่คือส่วนหัวทั้งหมดที่ระบุไว้ใน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
เป็นหรือvector
string
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()
จะทำงาน.