基础_2

参考:《算法竞赛入门经典》

一、浮点数的问题(尽量避免浮点运算)

浮点数的运算(或函数)有可能存在误差——不是一定存在,但经常都会

比如在经过大量计算后,由于误差的影响,整数 1 变成了 0.9999999999

1、floor 向下取整

floor(3.14) = 3
floor(9.999999) = 9
floor(-3.14) = -4
floor(-9.999999) = -10

floor(1.0) = 1

floor(x + 0.5) 即将下取整改为四舍五入形式

2、ceil 向上取整

floor(3.14) = 4
floor(9.999999) = 10
floor(-3.14) = -3
floor(-9.999999) = -9

floor(1.0) = 1

二、一些数学公式

1、三角形面积公式

海伦公式

p = (a + b + c) / 2.0

S = sqrt(p * (p - a) * (p - b) * (p - c))


2、圆台体积公式:(1.0/3.0)* PI * h * (R * R+r * r+R * r)

π的宏定义

#define PI acos(-1.0)
#define PI (atan(1.0) * 4.0)


三、

如果要从数组 a 复制 k 个元素到数组 b,可以这样做:memcpy(b, a, sizeof(int) * k)

当然了,如果数组 a 和 b 都是浮点型的,复制时要写成 memcpy(b, a, sizeof(double) * k)

如果需要把数组 a 全部复制到数组 b 中,可以写得简单一些:memcpy(b, a, sizeof(a))


四、

C 语言中,有一些字符直接表示出来不方便,例如回车符——它是 '\n',而空字符是 '\0',它也是 C 语言中字符串的结束标志

其他例子包括 '\\'(注意必须有两个反斜线)、'\''(这个是单引号),甚至还有的字符有两种写法:'\"' 和 '"' 都表示双引号

像这种以反斜线开头的字符称为转义序列


五、

strchr 函数:char *strchr(const char* _Str,char _Val)

功能:查找字符串_Str中首次出现字符_Val的位置
说明:返回首次出现_Val的位置的指针,返回的地址是被查找字符串指针开始的第一个与Val相同字符的指针,如果Str中不存在Val则返回NULL。


strcat 函数原型:extern char *strcat(char *dest, const char *src)
功能:把src所指字符串添加到dest结尾处(覆盖dest结尾处的'\0')
说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串
返回指向dest的指针


六、

用编译选项 -Wall 编译程序时,会给出很多(但不是所有)警告信息,以帮助程序员查错


七、用 fgets 而不是 gets

gets 和它的兄弟 fgets 差别比较大:它的用法是 gets(s),没有指明读取的最大字符数

这里就出现了一个潜在的问题:gets 将不停地往 s 里塞东西,而不管塞不塞得下!难道 gets 函数不去管 s 的可用空间有多少吗?你还真说对了


提示1:

C 语言并不禁止程序读写“非法内存”

例如你声明的是 char s[100],你完全可以赋值 s[10000] = 'a'(甚至 -Wall 也不会警告),但后果自负


提示2:

C 语言中的 gets(s) 存在缓冲区溢出漏洞,不推荐使用


解决“输入中有空格”的问题,我们选择的是 fgets 函数,它可以一次性读取一整行,最为方便


例:求最长回文子串

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#include <set>
#include <cmath>
#include <cctype>
#include <ctime>

using namespace std;

#define REP(i, n) for (int i = 0; i < (n); ++i)

typedef long long ll;
typedef pair<int, int> Pair;

const int INF = 0x7fffffff;
const int maxn = 5000 + 10;

char buf[maxn], str[maxn];
int pos[maxn];

int main() {
#ifdef __AiR_H
    freopen("in.txt", "r", stdin);
#endif // __AiR_H
    while (fgets(buf, sizeof(str), stdin)) {
        int cnt = 0, Max = 0, Left = 0, Right = 0;
        int len = strlen(buf);
        REP(i, len) {
            pos[cnt] = i;
            if (isalpha(buf[i])) { str[cnt++] = toupper(buf[i]); }
        }
        REP(i, cnt) {
            for (int j = 0; i - j >= 0 && i + j < cnt; ++j) {
                if (str[i - j] != str[i + j]) { break; }
                if (j * 2 + 1 > Max) {
                    Max = j * 2 + 1; Left = pos[i - j]; Right = pos[i + j];
                }
            }
            for (int j = 0; i - j >= 0 && i + j + 1 < cnt; ++j) {
                if (str[i - j] != str[i + j + 1]) { break; }
                if (j * 2 + 2 > Max) {
                    Max = j * 2 + 2; Left = pos[i - j]; Right = pos[i + j + 1];
                }
            }
        }
        for (int i = Left; i <= Right; ++i) {
            printf("%c", buf[i]);
        }
        printf("\n");
    }
#ifdef __AiR_H
    printf("Time used = %.2fs\n", (double)clock() / CLOCKS_PER_SEC);
#endif // __AiR_H
    return 0;
}


七、

printf("%d %o %x\n", a, a, a);

将把整数 a 分别按照十进制、八进制和十六进制输出


八、编写函数时,应尽量保证它能对任何合法参数都能得到正确的结果。如若不然,应在显著位置标明函数的缺陷,以避免误用

例、孪生素数

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#include <set>
#include <cmath>
#include <cctype>
#include <ctime>
#include <cassert>

using namespace std;

#define REP(i, n) for (int i = 0; i < (n); ++i)

typedef long long ll;
typedef pair<int, int> Pair;

const int INF = 0x7fffffff;

bool is_prime(int x);

int main() {
#ifdef __AiR_H
    freopen("in.txt", "r", stdin);
#endif // __AiR_H
    int m;
    scanf("%d", &m);
    for (int i = m - 2; i >= 3; --i) {
        if (is_prime(i) && is_prime(i + 2)) {
            printf("%d %d\n", i, i + 2); break;
        }
    }
#ifdef __AiR_H
    printf("Time used = %.2fs\n", (double)clock() / CLOCKS_PER_SEC);
#endif // __AiR_H
    return 0;
}

bool is_prime(int x) {
    assert(x >= 0);
    if (x == 1) { return false; }
    int m = floor(sqrt(x) + 0.5);
    for (int i = 2; i <= m; ++i) {
        if (x % i == 0) { return false; }
    }
    return true;
}

除了特判 n == 1 的情况,程序中还使用了变量 m,一方面避免了每次重复计算 sqrt(x)

另一方面也通过四舍五入避免了浮点误差——如果 sqrt “不小心”把某个本应是整数的值弄成了 xxx.99999,也将被修正

但直接写 m = sqrt(x) 的话那个 “.99999” 会被无情地截掉

最后,程序使用了 cassert 中的 assert 宏来限制非法的函数调用:当 x >= 0不成立时,程序将异常终止,并给出提示信息

检查非法参数是很有用的的:当算法很复杂时,一不小心就会用非法参数调用某些自定义函数,如果函数不对参数进行检查,则很可能让程序得到一个荒唐的结果

如果函数调用关系非常复杂,是难以查出错误的根源的

如果每个函数都检查参数,就能较快地找出“罪魁祸首”


提示:编程时合理地利用 assert 宏,将给调试带来很大的方便


总而言之,在实际的系统中,“一个地方的参数错误就引起整个程序异常退出”是不可取的,在编写和调试算法程序中,assert 会“迫使”我们编写出更高质量的程序


九、Vijos P1333 Cantor表

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#include <set>
#include <cmath>
#include <cctype>
#include <ctime>
#include <cassert>

using namespace std;

#define REP(i, n) for (int i = 0; i < (n); ++i)

typedef long long ll;
typedef pair<int, int> Pair;

const int INF = 0x7fffffff;

int main() {
#ifdef __AiR_H
    freopen("in.txt", "r", stdin);
#endif // __AiR_H
    int N;
    while (scanf("%d", &N) != EOF) {
        int s = 0, k = 1;
        while (1) {
            s += k;
            if (s >= N) {
                if (k & 1) {
                    printf("%d/%d\n", s - N + 1, k - s + N); break;
                }
                printf("%d/%d\n", k - s + N, s - N + 1); break;
            }
            ++k;
        }
    }
#ifdef __AiR_H
    printf("Time used = %.2fs\n", (double)clock() / CLOCKS_PER_SEC);
#endif // __AiR_H
    return 0;
}


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#include <set>
#include <cmath>
#include <cctype>
#include <ctime>
#include <cassert>

using namespace std;

#define REP(i, n) for (int i = 0; i < (n); ++i)

typedef long long ll;
typedef pair<int, int> Pair;

const int INF = 0x7fffffff;

int main() {
#ifdef __AiR_H
    freopen("in.txt", "r", stdin);
#endif // __AiR_H
    int N;
    while (scanf("%d", &N) != EOF) {
        int k = (int)floor((sqrt(8.0 * N + 1) - 1) / 2 - 1e-9) + 1;
        int s = k * (k + 1) / 2;
        if (k & 1) {
            printf("%d/%d\n", s - N + 1, k - s + N); continue;
        }
        printf("%d/%d\n", k - s + N, s - N + 1);
    }
#ifdef __AiR_H
    printf("Time used = %.2fs\n", (double)clock() / CLOCKS_PER_SEC);
#endif // __AiR_H
    return 0;
}


十、三角形有向面积



UVa 143 Orchard Trees

注意:树的坐标 (x,y) 的值为区间 [1, 99] 内的整数

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#include <set>
#include <cmath>
#include <cctype>
#include <ctime>
#include <cassert>

using namespace std;

#define REP(i, n) for (int i = 0; i < (n); ++i)
#define eps 1e-9

typedef long long ll;
typedef pair<int, int> Pair;

const int INF = 0x7fffffff;
double x_0, y_0, x_1, y_1, x_2, y_2;
int x_left, y_left, x_right, y_right;

double area2(double _x_0, double _y_0, double _x_1, double _y_1, double _x_2, double _y_2) {
    return (_x_0 * _y_1 - _x_1 * _y_0) + (_x_1 * _y_2 - _x_2 * _y_1) + (_x_2 * _y_0 - _x_0 * _y_2);
}

bool judge(double x, double y);

int main() {
#ifdef __AiR_H
    freopen("in.txt", "r", stdin);
#endif // __AiR_H
    while (scanf("%lf %lf %lf %lf %lf %lf", &x_0, &y_0, &x_1, &y_1, &x_2, &y_2) != EOF) {
        if (x_0 + y_0 + x_1 + y_1 + x_2 + y_2 < eps) { break; }
        double t = min(x_0, min(x_1, x_2)); x_left = max(1, (int)ceil(t));
        t = max(x_0, max(x_1, x_2)); x_right = min(99, (int)floor(t));
        t = min(y_0, min(y_1, y_2)); y_left = max(1, (int)ceil(t));
        t = max(y_0, max(y_1, y_2)); y_right = min(99, (int)floor(t));
        int ans = 0;
        for (int i = x_left; i<= x_right; ++i) {
            for (int j = y_left; j <= y_right; ++j) {
                if (judge((double)i, (double)j)) { ++ans; }
            }
        }
        printf("%4d\n", ans);
    }
#ifdef __AiR_H
    printf("Time used = %.2fs\n", (double)clock() / CLOCKS_PER_SEC);
#endif // __AiR_H
    return 0;
}

bool judge(double x, double y) {
    double t = fabs(area2(x_0, y_0, x_1, y_1, x_2, y_2));
    double a = fabs(area2(x, y, x_1, y_1, x_2, y_2));
    double b = fabs(area2(x_0, y_0, x, y, x_2, y_2));
    double c = fabs(area2(x_0, y_0, x_1, y_1, x, y));
    if (fabs(t - a - b - c) < eps) { return true; }
    return false;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值