C ++でゴルフをするための一般的なヒントは何ですか?私は少なくともC ++に特有のゴルフ問題全般のコーディングに適用できるアイデアを探しています(たとえば、「コメントを削除する」は答えではありません)。回答ごとに1つのヒントを投稿してください。
C ++でゴルフをするための一般的なヒントは何ですか?私は少なくともC ++に特有のゴルフ問題全般のコーディングに適用できるアイデアを探しています(たとえば、「コメントを削除する」は答えではありません)。回答ごとに1つのヒントを投稿してください。
回答:
三項条件演算子は?:
、多くの場合、単純なためでスタンドとして使用することができますif
- else
かなりの節約に文。
次のように代替の左辺値を選択するために使用できるという点で特別な値です。
#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
andのいずれかへの参照o
です。これは、cでこの演算子がどのように機能するかとは異なります。この場合、このトリックは左辺値になれないため機能しません。
std::endl
て'\n'
5文字節約
一部のコンパイラ(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(および他の2のべき乗の組み合わせ)を使用すると、x * y = 0も生成されます。
&&
これに*
は短絡動作がありません。たとえば、あなたが交換することはできませんi++!=0&&j++!=0
とi++*j++
。
次のタイプを使用します。
u64, s64, u32, s32 (or int)
繰り返される単語/タイプには、次を使用します#defines
。
#define a while
while
余分な10文字を補うために多くを使用する場合にのみ価値があります。(約4。)
可能な場合は、それぞれ&&
と||
を変更&
し|
ます。
単純なifステートメントを使用する場合:
if(<condition>)<stuff>;
次のように変更できます。
<condition>?<stuff>:<any single letter variable>;
キャラクターを保存します。
配列要素は、次のようなものではなく、メモリ内に次々と直接格納されるため:
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++)
?次に、1つの変数のみを追跡する必要があります。
かなり明白なものですが、多くの標準ライブラリを使用しているusing namespace std;
ため、数文字を節約できます。
using std::name;
短くなる場合があります。
std::
5回以上使用する場合にのみ文字を保存します。
10のべき乗を書く代わりに、e notationを使用します。たとえば、a=1000000000
はより長いですa=1e9
。これは、のような他の番号に拡張することができるa=1e9+24
よりも優れていますa=1000000024
。
1e9/x
は1000000000/x
異なりint(1e9)/x
ます。
?:
trueブロックに式を指定せずに三項演算子を使用できます(バイトを保存します)
#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)
ブールの算術演算:
でも
a*=b>0?.5:-.5
よりも良い
if(b>0)a*=.5;else a*=-.5;
あまり良くない
a*=(b>0)-.5
また、よく使用されるものには#defineを使用します。多くの場合、型名は必要ないため、関数を使用するよりも短くなります。
可能な限り組み合わせる
a+=a--;
と同じです
a=2*a-1;
以外の型の場合int
、関数の引数として使用するとコストが高くなる可能性があります。ただし、一般的なラムダが(C ++ 14で?)導入され、任意のラムダをテンプレートにauto
することができます- 引数型に使用するとバイトを節約できます。比較:
double f(double x, double y)
[](auto x, auto y)
C ++での配列の入力を受け入れるように、おそらく最良の方法である-ジェネリックラムダも受け入れてイテレータのために非常に便利です[](auto a, auto z)
、a
とz
として渡されるbegin()
とend()
などのアレイ/ベクトル/リスト/で。
タスク「次の数字を引く」のコードゴルフの最初の試みで、関数から開始しました(58バイト)
int f(int N, int P){int F;for(F=N;P;F-=++N,P--);return F;}
その後、ラムダにシフトし、for
(53)から初期化を移動して、5バイトを安全にします
[](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;
}
更新:
実際にfor
同じ長さに達することができますwhile
:
[](int N,int P){int F=N;for(;P--;F-=++N);return F;}
パーティーに遅刻したようだ...
式をこれの代わりに0と1ではなく-1と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バイト短くなっていますか?
2つの整数変数aとbを交換する場合、
a^=b^=a^=b;
使用することができ、標準的な方法よりも5文字を節約する
a+=b;
b=a-b;
a-=b;
,t
intで以前に作成されて、それから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
可能であれば、複合型にしてください。
例:66ではなく54バイト
#include<vector>
std::vector<int> f(std::vector<int> l){return l;}
#include<vector>
auto f(std::vector<int> l){return l;}
また、パフォーマンスは重要ではないため、一部の課題でstd::list
は、数バイト少ないジョブを実行できます。
#include<list>
auto f(std::list<int> l){return l;}
使用しないでくださいstring("")
、使用を""
。8バイトを節約します。
"" + 'a'
あるchar* + char
ながら、ポインタ加算である、std::string("") + 'a'
であるstd::string + char
-文字列の連結。string()
動作します。