在C ++中打高尔夫球的技巧


48

您在C ++中打高尔夫球有哪些一般技巧?我正在寻找可以应用于一般高尔夫问题代码的想法,这些想法至少在某种程度上是C ++特有的(例如,“删除注释”不是答案)。请为每个答案发布一个提示。


4
使用C语言打高尔夫球的许多技巧也适用于C ++,因此请假定读者熟悉该问题。仅当您的内容也不是有效的C高尔夫技巧时,才在此处发布。
Toby Speight

@TobySpeight可能是因为问题ID之外的URL相同。
NoOneIsHere

C和C ++,即使不是'golfing'类型,也都是正确且容易的(如果考虑到C ++的正确子集)
RosLuP

Answers:


24

三元有条件的经营者?:往往可以用作简单的一个立场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;
}

还没有运行代码,但是我认为它不能像您所说的那样工作。((u = atoi(v [c]))%2?o:e)+ = u除了将值u添加到左侧的表达式(其获得值o或e)外,什么都没有做,但是变量o和e保持不变,因此它们始终为0。检查代码以了解发生了什么情况。您应该使用地址使其有效
Bogdan Alexandru

4
@BogdanAlexandru Er ...运行它。它确实有效。括号表达式的值是一个参考或其它的eo。请注意,这与该运算符在c中的工作方式不同,在c中此技巧不起作用,因为它不能为左值。
dmckee,2012年

更换std::endl'\n',节省了5个字符
穆库尔·库马尔

3
@MukulKumar好吧,是的。但是为了演示技巧,为了清楚起见,我将除三元条件之外的所有内容都保留了下来。
dmckee 2014年

22

有时,您可以利用以下事实来保存两个字符:静态存储持续时间变量(尤其是包括所有全局作用域变量)在开始时会自动进行零初始化(与没有这种保证的自动变量不同)。所以代替

int main()
{
  int a=0;
  // ...
}

你可以写

int a;
int main()
{
  // ...
}

+1但绝对是不好的做法
mondlos

@mondlos:打高尔夫球基本上意味着不好的作法。
celtschk

15

一些编译器(例如GCC)支持多字符常量。当需要大整数值时,这可以节省一些字符。例:

int n='  ';

该值是特定于实现的。通常,'ab'is 256*'a'+'b'或的值'a'+256*'b'。引号之间最多可以指定4个字符。


3
海湾合作委员会?你是说g ++
内森·奥斯曼

6
@George爱迪生:GCC代表的GNU编译器,其包括其所有的前端,包括那些为C,C ++,围棋,等等
乔伊亚当斯

@Joey:我知道,但是它也是GNU C编译器的名称。
内森·奥斯曼

25
@乔治:GNU C编译器称为gcc,而不是GCC。
fredoverflow

也许还记得,我可能会忘记。

12

我觉得很方便的一个:

利用非零值true在布尔表达式中x&&y求值,以及x*y在处理布尔值时求值的事实

(x!=0 && y!=0)

评估为

(x*y)

您只需要注意溢出,如下所述。


2
从技术上讲,它是x!=0 && y!=0。但是在使用乘法时,您需要小心溢出。当使用32位整数x = y = 65536(以及其他两种幂的组合)时,x * y = 0
Martin Ender 2014年

是的,这是正确的。我在这里将其用作二维数组边界检查:codegolf.stackexchange.com/a/37571/31477在哪里都没关系。我会在编辑这些点。
Baldrickk

1
但是请注意,这种&&短路行为*缺乏。例如,您不能将替换i++!=0&&j++!=0i++*j++
celtschk

@celtschk是的,很好。但是,如果您纯粹是布尔布尔代数,那么它就起作用了
Baldrickk

11

使用以下类型:

u64, s64, u32, s32 (or int)

对于重复的单词/类型,请使用#defines

#define a while

仅当您使用while大量字符来弥补额外的10个字符时才值得。(约4个。)


1
u64,s64,u32和s32类型不属于C ++。它们可能是编译器的非标准扩展(尽管我从未见过)。
celtschk 2014年

5
最好将这两个技巧放在两个单独的答案中,以便分别进行投票。
trichoplax


10

如果可能的话,改变&&||&|分别。

使用简单的if语句时:

if(<condition>)<stuff>;

可以更改为:

<condition>?<stuff>:<any single letter variable>;

保存一个字符。


8

代替使用while(1),而是使用for(;;)保存一个字符:)


8

如果您的子句中有多个语句,则使用逗号运算符代替大括号可以节省一些字符:

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 ++中的逗号表达式的结果可用作左值... FWIW。


7

由于数组元素彼此紧接着直接存储在内存中,而不是像这样的东西:

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;

显然,上述两种方法都不易理解,但是为了明确起见,使用指针可以节省大量空间。


别忘了您可以删除所有空白!(总共有不同的提示,但应该提及)
随机2014年

@stokastic这些示例并非旨在打高尔夫,仅是为了演示如何使用该技术。
Stuntddude

6
为什么不for(int* i=array; i<array+25*25; i++)呢?然后,您只需要跟踪一个变量即可。
卢卡斯2015年

6

很明显,但是您使用了很多标准库,using namespace std;可能会节省一些字符。


5
但是,如果您仅使用一个名称,则该名称using std::name;可能会更短。
celtschk 2014年

10
如果您使用std::五次或更多次,这只会保存字符。
nyuszika7h 2014年

6

记住a[i]与相同是很有用的*(a+i)

更换a[0]*a两个字符的节省。同样,a[i][0]等于*a[i]a[0][i]缩小为i[*a]。因此,如果您要0对数组中的索引进行硬编码,则可能存在更好的方法。


5

不用写10的大幂,而是使用e表示法。例如,a=1000000000长于a=1e9。可以扩展到其他数字,例如a=1e9+24优于a=1000000024


1
请注意,这并不完全等效,使用前需要转换为整数类型。例如1e9/x1000000000/x或不同int(1e9)/x
user202729

5

您可以?:在true块中使用不带任何表达式的三元运算符(节省一个字节)

#include <iostream>

int foo()
{
    std::cout << "Foo\n";
}

int main()
{
    1?foo():0;  // if (true) foo()
    0?:foo();   // if (!false) foo()
}

在这里检查



r?foo():0; //如果(r)foo()没关系;;;;; 但是为此r?:foo(); 我不知道
RosLuP

5

标头较短

这是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)

4

#import而不是#include再给您一个字节。

此外,#import和标头之间的空格字符不一定是:

#include <map>
// vs
#import<map>

并且,如果您需要stdlib标头中的某些内容,则可以使用STL容器(首选setmap)而不是导入任何标头cstdlib


3

布尔运算:

虽然

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用作左值和x++右值时,请小心调用未定义的行为。未定义的行为和顺序点
ceilingcat

是可能的a + = a--; 具有未定义的行为
RosLuP

3

使用通用Lambda作为廉价模板

对于以外的类型int,将它们用作函数参数可能会很昂贵。但是,引入了通用Lambda(在C ++ 14中),并且允许将任何Lambda用作模板- auto用于参数类型可以节省字节。相比:

double f(double x, double y)
[](auto x, auto y)

通用的lambda也用于接受迭代器很方便-可能在C ++接受阵列输入的最好的方法是[](auto a, auto z),其中,az作为传递begin()end()阵列/向量/列表/等。


2

在我第一次尝试通过代码高尔夫完成“减去下一个数字”任务时,我从功能(58字节)开始

int f(int N, int P){int F;for(F=N;P;F-=++N,P--);return F;}

然后安全地转移到lambda并将初始化从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;}

2

我想晚会有点晚...

如果要将表达式转换为-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个字节?
girobuz

2

如果要交换两个整数变量a和b,

a^=b^=a^=b;

可以使用,比标准方式节省5个字符

a+=b;
b=a-b;
a-=b;

1
关于这种标准方式。,t在较早创建的int处,然后t=a;a=b;b=t;将比a+=b;b=a-b;a-=b;。短3个字节。不过,您a^=b^=a^=b;的身材比这还矮,所以请+1。我不懂C ++,但确实可以。作为Java代码访问者,我感到遗憾的是,那里似乎不起作用。:(
Kevin Cruijssen

1
@KevinCruijssen是的,我应该提到C ++,我不太了解Java,但是a^=b;b^=a;a^=b;在Java中运行良好。
joker007

1
无需明确提及C ++。所有这些技巧都是针对C ++的。:)作为Java开发人员,我只是想知道是否可以在Java中完成类似的操作,但显然不能。a^=b;b^=a;a^=b;确实有效,但比,t+长t=a;a=b;b=t;。抱歉提到Java,因为它不在这里。但是对于C ++代码编写者来说是一个不错的提示!
凯文·克鲁伊森

2

使用GCC内置函数而不是导入

如果您使用的是GCC编译器,则有时可以使用它们的内置函数,例如__builtin_puts__builtin_clz。例如,

44个字节:

int main(){__builtin_puts("Hello, world!");}`

50个字节:

#import<cstdio>
int main(){puts("Hello, world!");}

1

如果您使用的是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;}

同样,由于性能并不重要,因此对于某些挑战,std::list可以将工作量减少几个字节:

#include<list>
auto f(std::list<int> l){return l;}

1

函数<algorithm>通常需要传递a.begin(),a.end()很长的时间,&a[0],&*end(a)如果ais vector或,则可以用来保存3个字节string

sort(a.begin(),a.end());
sort(begin(a),end(a));
sort(&a[0],&*end(a));

0

不要用string(""),用""。节省8个字节。


这并不完全等效。例如"" + 'a'char* + char,它是指针此外,虽然std::string("") + 'a'std::string + char-字符串连接。string()会工作。
user202729
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.