HaiFeng's profile因为选择,所以喜欢!PhotosBlogListsMore Tools Help

因为选择,所以喜欢!

ACM算法博客 http://chenhaifeng.blog.edu.cn

[C++] 字符串和流

第一节、字符串操作

一、char_traits 字符特征类
1)意义:包装特定串元素的通用行为界面,以便容器实现时依据特征信息而执行特定行为
2)定义了通用类型名

typedef _Elem char_type;
typedef int int_type;
typedef streampos pos_type;
typedef streamoff off_type;
typedef mbstate_t state_type;

其中 int_type 表示字符元素转换到特定编码时的整型表示,pos_type, off_type 分别作为字符串索引和字符串元素偏移的类型,类似容器迭中的指针,迭代类型和指针,迭代器的偏移类型。最后的 state_type 用于存储流状态,如出错,格式控制等等。

3)定义了字符 / 字符串操作的包装界面,以便通用算法的调用

assign(a, b) 定义将 b 字符赋值给 a 字符的过程,实现 a.operator = 的行为
eq(a, b) 定义 a 字符和 b 字符的相等关系,实现 a.operator == 的行为
lt(a, b) 定义 a 小于 b 的关系,实现 a.operator < 的行为
compare(a_ptr, b_ptr, cnt) 定义两组字符串的比较,返回 int 类型,实现类似 memcmp 的行为
length(ptr) 定义取字符串长度,实现类似 strlen 的行为
copy(a_ptr, b_ptr, cnt) 定义两组字符串的复制,实现类似 memcpy 的行为
move(a_ptr, b_ptr, cnt) 定义两组字符串的不重叠复制,实现类似 memmove 的行为
assign(ptr, cnt, ch) 定义了填充字符串的过程,实现类似 memset 的行为
to_int_type(ch) 定义了 char_type 到 int_type 整型的转换过程
to_char_type(n) 定义了 int_type 到 char_type 字符型的转换过程
eq_int_type(a, b) 定义两个和当前 char_type 类型对应的 int_type 的相等关系
eof() 定义字符串结尾符,使用整型表示
not_eof(n) 定义非字符串结尾符,若输入结尾符,则返回 1,其他输入返回原值,即总是不返回 eof()

4)int_type 类型应是当前字符类型的整型编码

二、std::string 并不是序列容器,没有 front() 和 back() 界面用于取出前端和尾端的元素,使用 std::string::operator [] 并传递 streampos 类型取得特定元素,如 std::string::size() - 1 作为索引取得最后一个字符

三、basic_string 支持的初始化
1)默认初始化
2)分配器
3)复制构造
4)局部复制 [_Roff, _Roff + _Count)
5)局部复制 + 分配器
6)C 字符串 [_Ptr, <null>)
7)C 字符串 + _Count [_Ptr, _Ptr + _Count)
8)C 字符串 + 分配器
9)C 字符串 + _Count + 分配器 [_Ptr, _Ptr + _Count)
10)_Count * _Ch
11)_Count * _Ch + 分配器
12)迭代器 [_ItF, _ItL)
13)迭代器 + 分配器

字符到串不能初始化,但支持 operator = 赋值和 operator += 累加赋值运算。

四、字符串的区间有效性
对串的索引访问在超过字符串的有效区间时,因为串的在实现上对内置的字符缓冲区执行下标访问,所以不会导致异常,但是将得到不可预知的结果,通常是不可用的。
将其他字符串作为右值输入时,对该串取出计数大于串大小时按串大小计算。
std::basic_string::size_type 的实际类型为 size_t,在 Visual C++ 7.1 中实现为 unsigned,std::basic_string::npos 被静态设定为

(basic_string<_Elem, _Traits, _Alloc>::size_type)(-1);

在查找子字符串等操作时,函数返回 npos 的值表示非法索引。

五、比较字符串
允许的比较对象
1)compare(s2) 其他同类型字符串
2)compare(p) C 风格字符串
3)compare(off, cnt, s2) [off, off + cnt) 同 s2 执行比较
4)compare(off, cnt, s2, off2, cnt2) [off, off + cnt) 同 s2 [off2, cnt2) 执行比较
5)compare(off, cnt, p) [off, off + cnt) 同 [p , <null>) 执行比较
6)compare(off, cnt, p, cnt2) [off, off + cnt) 同 [p, p + cnt2) 执行比较

返回 -1, 0, 1 作为小于、等于和大于的比较结果。

六、附加数据
1)使用 operator += 接受其他字符串,C 风格字符串和字符
2)使用 push_back() 在尾部附加字符,并使得通过字符串构造的 back_iterator 可以访问
3)append() 附加
        1、append(s) 追加字符串
        2、append(s, off, cnt) 追加字符串 s [off, off + cnt)
        3、append(p) 追加字符串 [p, <null>)
        4、append(p, cnt) 追加字符串 [p, p + cnt)
        5、append(n, c) 填充 n * c
        6、append(InF, InL) 追加输入流 [InF, InL)

4)insert() 插入
        1、insert(off, s2) 插入字符串
        2、insert(off, s2, off2, cnt2) 插入字符串 s [off2, off2 + cnt2)
        3、insert(off, p) 插入字符串 [p, <null>)
        4、insert(off, p, cnt) 插入字符串 [p, p + cnt)
        5、insert(off, n, c) 插入 n * c
        6、insert(iter) 元素默认值填充
        7、insert(iter, c) 插入特定元素
        8、insert(iter, n, c) 插入 n*c
        9、insert(iter, InF, InL) 插入 [InF, InL)

5)operator +(a, b)
字符串关联运算符重载中支持 operator + 的形式
        1、s + s
        2、s + p
        3、s + c
        4、p + s
        5、c + s

七、查找、替换和清除
1)find() 查找
        1、find(c, off) 在 s [off, npos) 中查找 c
        2、find(p, off, n) 在 s [off, npos) 中查找 [p, p + n)
        3、find(p, off) 在 s [off, npos) 中查找 [p, <null>)
        4、find(s2, off) 在 s [off, npos) 中查找 s2

2)find() 的变种
        1、rfind() 具有 find() 的输入形式,反序查找
        2、find_first_of() 具有 find() 的输入形式,返回第一个匹配的索引
        3、find_last_of() 具有 find() 的输入形式,返回倒数第一个匹配的索引
        4、find_first_not_of() 具有 find() 的输入形式,返回第一个不匹配的索引
        5、find_last_not_of() 具有 find() 的输入形式,返回倒数第一个不匹配的索引

3)replace() 替换
        1、replace(off, cnt, s2) 将 s [off, off + cnt) 替换成 s2
        2、replace(off, cnt, s2, off2, cnt2) 将 s [off, off + cnt) 替换成 s2 [off2, off2 + cnt2)
        3、replace(off, cnt, p) 将 s [off, off + cnt) 替换成 [p, <null>)
        4、replace(off, cnt, p, cnt2) 将 s [off, off + cnt) 替换成 [p, p + cnt2)
        5、replace(off, cnt, n, c) 将 s [off, off + cnt) 替换成 c * n

使用迭代器的情况:
        6、replace(InF, InL, s2) 将 [InF, InL) 替换成 s2
        7、replace(InF, InL, p) 将 [InF, InL) 替换成 [p, <null>)
        8、replace(InF, InL, p, cnt) 将 [InF, InL) 替换成 [p, p + cnt)
        9、replace(InF, InL, n, c) 将 [InF, InL) 替换成 n * c
        10、replace(InF, InL, InF2, InL2) 将 [InF, InL) 替换成 [InF2, InL2)

4)erase() 删除
        1、erase(off, cnt) 从字符串 s 中删除 s [off, off + cnt)
        2、erase(iter) 从字符串 s 中删除 *iter
        3、erase(ItF, ItL) 从字符串 s 中删除 [ItF, ItL)

八、取出字符串
1)取得 C 风格字符串
c_str() 返回常量类型的 C 风格字符串指针,copy(ptr, cnt, off = 0) 则将指定大小的字符串复制到特定指针。data() 在 Visual C++ 7.1 中仅仅调用了 c_str() 实现。

2)取得子字符串
substr(off, cnt) 取得 s [off, off + cnt) 的副本。

3)复制子字符串
copy(p, off, cnt) 将 s [off, off + cnt) 复制到 p。

九、字符串的缓冲区管理
字符串具有类似 std::vector 的缓冲区管理界面。

size() 取得有效元素长度
max_size() 取得当前内存分配器能分配的有效空间
reserve() 为缓冲区预留空间
capacity() 取得缓冲区的容量
resize() 重设串的长度,可以为其指定初始化值

十、定义输入迭代器的尾端
向 istream_iterator 传递输入流对象以创建输入迭代器,输入迭代器持有输入流对象的指针,默认创建和读取流失败的情况下该指针被设置为 0。并且在实现输入迭代器间的 operator == 相等运算时,进行持有的流对象指针的相等比较,这样,默认创建的输入迭代器将被用于匹配输入流的结束。

* 当输入流读取失败,用户执行 if, while 条件判断时,实际上先将判断值转换成 void* 类型,或者根据 operator ! 运算符的返回结果,对输入流重载 operator void* 和 operator ! 运算符,可以定义输入流在布尔表达式中的行为,使得当流读取失败的情况下,输入迭代器可以通过布尔表达式来确认,而不是显式访问 fail() 成员函数:

void _Getval()
        {       // get a _Ty value if possible
        if (_Myistr != 0 && !(*_Myistr >> _Myval))
                _Myistr = 0;
        }

上式的 std::basic_istream::operator >> 将返回 std::basic_istream& 类型,该类型又具有如下的运算符重载:

operator void *() const
        {       // test if any stream operation has failed
        return (fail() ? 0 : (void *)this);
        }

bool operator!() const
        {       // test if no stream operation has failed
        return (fail());
        }

十一、C 风格字符串
1)字符串操作
strcpy(p, p1) 复制字符串
strncpy(p, p1, n) 复制指定长度字符串
strcat(p, p1) 附加字符串
strncat(p, p1, n) 附加指定长度字符串
strlen(p) 取字符串长度
strcmp(p, p1) 比较字符串
strncmp(p, p1, n) 比较指定长度字符串
strchr(p, c) 在字符串中查找指定字符
strrchr(p, c) 在字符串中反向查找
strstr(p, p1) 查找字符串
strpbrk(p, p1) 以目标字符串的所有字符作为集合,在当前字符串查找该集合的任一元素
strspn(p, p1) 以目标字符串的所有字符作为集合,在当前字符串查找不属于该集合的任一元素的偏移
strcspn(p, p1) 以目标字符串的所有字符作为集合,在当前字符串查找属于该集合的任一元素的偏移

* 具有指定长度的字符串处理函数在已处理的字符串之后填补零结尾符

2)字符串到数值类型的转换
strtod(p, ppend) 从字符串 p 中转换 double 类型数值,并将后续的字符串指针存储到 ppend 指向的 char* 类型存储。
strtol(p, ppend, base) 从字符串 p 中转换 long 类型整型数值,base 显式设置转换的整型进制,设置为 0 以根据特定格式判断所用进制,0x, 0X 前缀以解释为十六进制格式整型,0 前缀以解释为八进制格式整型
atoi(p) 字符串转换到 int 整型
atof(p) 字符串转换到 double 符点数
atol(p) 字符串转换到 long 整型

3)文本转换成 long 类型超出表示范围时将设置 C 运行时的 errno 全局变量,errno == ERANGE,使用 strerror(errno) 来取得错误对应的字符串

4)字符检查
isalpha() 检查是否为字母字符
isupper() 检查是否为大写字母字符
islower() 检查是否为小写字母字符
isdigit() 检查是否为数字
isxdigit() 检查是否为十六进制数字表示的有效字符
isspace() 检查是否为空格类型字符
iscntrl() 检查是否为控制字符
ispunct() 检查是否为标点符号
isalnum() 检查是否为字母和数字
isprint() 检查是否是可打印字符
isgraph() 检查是否是图形字符,等效于 isalnum() | ispunct()

第二节、输入输出流

一、输出流

二、各种类型流输出 operator << 重载
输出流不仅接受可显示的数据类型,同时接受操纵符影响输出流的行为并返回输出流的引用,以便使用 operator << 串接一组的操作。
以下列出一些特定的输出类型及其用法和实现概要。

1)为单个字符的输出直接调用 put() 而不必使用 operator <<
2)为操纵符重载 operator <<
std::hex 是输出流的操纵符之一,被实现为接受基本流类型引用,并更改其状态为输出十六进制的函数:

inline ios_base& __cdecl hex(ios_base& _Iosbase)
        {       // set basefield to hex
        _Iosbase.setf(ios_base::hex, ios_base::basefield);
        return (_Iosbase);
        }

输出流的一个重载版本将代为访问该操纵符:

_Myt& operator<<(ios_base& (__cdecl *_Pfn)(ios_base&))
        {       // call ios_base manipulator
        (*_Pfn)(*(ios_base *)this);
        return (*this);
        }

最后,当前输出流对象的引用被返回,以串接其他 operator << 操作,通过操纵符的应用,将可以得到类似以下的访问形式:

std::cout << std::setw(10) << std::internal << std::hex << std::uppercase << std::showbase << std::setfill('0') << int(768 * 1024) << std::endl;
3)std::boolalpha 操纵符指示输出流使用符号形式表示真假
4)对于指针类型,输出十六进制以表示地址格式,并且即使使用 std::showbase 以指示输出流输出进制的前缀及其他试图影响指针类型数据的输出格式的操纵符,该指针的地址格式不会发生变化

int* p = std::auto_ptr<int>(new int).get();
std::cout << p << std::endl;

三、输入流的分割
operator >> 按空白类型——即 isspace() 对应的字符类型:blank, vertical table, horizontal table, return, newline, newpage 等——分割输入流。当然,对于具有格式要求的输入类型,则在未匹配处中止。
1)std::cin >> intval;
int 类型读入非预期的数据,设置 ios_base::failbit 到流状态。std::cin.rdstate() & std::ios_base::failbit 以获取该状态。

2)std::cin.width(n);
显式指示字符串读入的数据长度,以防止目标存储的溢出,包括为目标存储自动添加的 '\0',若传递给std::string 等标准库字符串类型则不包含尾端的 '\0' 空字符,传递到其他类型不受该宽度的限制,且仅影响下一次的输入操作。

四、流状态
1)意义:调用者通过对状态的访问,以了解流的操作结果和存在的异常
good() 测试 goodbit
eof() 测试 eofbit
fail() 测试 badbit | failbit
bad() 测试 badbit
rdstate() 取得流状态
clear([flag]) 清除 / 设置流状态
setstate(flag) 附加流状态

2)异常的流导致下次读取将失效

五、测试流对象的布尔值
bool operator !() 否定式。
operator void *() 作条件式判断,编译器强制转型到 void*,此时可以返回 0 以表示 false。

六、非格式化输入
int_type get() 从输入流取出 int_type 类型数据,对应单个特定类型编码字符
get(c) 取出字符类型数据
get(p, n) 取得 n 长度的字符串到 p,按换行符分割
get(p, n, delim) 取出 n 长度的字符串到 p,指定分割符
ignore(n, delim) 忽略 n 长度的字符串,指定分割符
read(p, n) 读入 n 个字符
gcount() 获得最后一次非格式化输入的取出字符长度

get(p, n, delim) 并不取出 delim 本身,这和 getline 是不同的,用户在需要的情况下必须手动附加到目标串。另外,连续出现的分隔符将导致取出空字串,ios_base::failbit 被附加到流状态,这将导致对 get() 的条件判断失败。

七、流异常
ios_base::exceptions() 获取异常掩码
ios_base::exceptions(iostate) 设置异常掩码
ios_base::failure 流的异常类

附加到异常掩码的状态位将使得流遭遇特定状态时抛出 ios_base::failure 异常。

八、流联结
basic_ios::tie() 取出和输入流联结的输出流指针
basic_ios::tie(basic_ostream&) 设置和输入流联结的输出流指针

* 和输入流联结的输出流总是在输入流请求输入前刷新输出流状态,使用 basic_ostream::flush(),在文件流中表现为立即写入到磁盘文件。

九、sentry
1)意义:sentry 是输入输出流对象的一组自动对象,使用其构造函数和析构函数,负责在流操作中执行预处理和后处理,例如,为流缓冲区附加线程锁

2)sentry 对象类型执行条件判断时,隐式转换到 bool 类型,指针类型则转换到 void* 类型。重载 sentry::operator bool(),以便从 sentry 返回流的可用状态,以便指导流的实际动作,如线程冲突可能导致流不可用,sentry 必须提供该类信息

第三节、输出流格式

一、ios_base 格式设置
        flags() 读标志位
        flags(fmt) 设置标志位
        setf(fmt) 附加标志位
        setf(fmt, mask) 根据掩码附加标志位
        unsetf(mask) 清除掩码位置的标志

* setf(fmt) 和 setf(fmt, mask) 有一个重要的区别,对于位于同一个掩码值以下的所有位,在具有掩码输入的情况下将被事先清除,这将保证在该掩码值以下的标志位的设定具有互斥的特性,而 setf(fmt) 将可能在同一个掩码值下的所有位出现多个置位的选项。

二、控制输出流格式位的操纵符
用于控制输出流格式的操纵符大部分位于 <ios> 文件以下。它们可以被附加到 basic_ostream::operator <<() 后端并影响对应的输出流。
1)对齐格式 adjustfield
        right 右侧对齐,默认设置
        left 左侧对齐
        internal 内部对齐

2)基数 basefield
        dec 十进制,默认设置
        hex 十六进制
        oct 八进制

4)符点 floatfield
        scientific 科学计数法
        fixed 定点数

3)输出
        showbase / noshowbase 显示进制修饰前缀
        showpoint / noshowpoint 总是打印尾部的小数位,包括为 0 的情况,默认 noshowpoint
        boolalpha / noboolalpha 使用字符串打印布尔值,默认 noboolalpha
        showpos / noshowpos 打印符号,包括正数的情况,默认 noshowpos
        skipws / noskipws 跳过空白字符处,默认 noskipws
        uppercase / nouppercase 十六进制用数字字符为大写格式,默认 nouppercase

5)掩码
        ios_base::adjustfield = ios_base::right | ios_base::left | ios_base::internal
        ios_base::basefield = ios_base::dec | ios_base::hex | ios_base::oct
        ios_base::floatfield = ios_base::scientific | ios_base::fixed

* 掩码中使用的标志位命名和操纵符可能同名,但不是指同一符号。

三、使用 skipws 使输入流忽略空白
通过忽略输入流的空白字符,帮助有效获取数值等类型而避免失败。

std::cin >> std::noskipws;
std::cin.exceptions(cin.failbit);
std::cin >> intval;

若对以上例程输入包含起始处空格的字符串,则抛出异常,空白字符不是有效的数值格式字符。

四、浮点输出
        ios_base::precision() 获取浮点数精度,默认为 6
        ios_base::precision(n) 设置精度

* 对于默认的 float 输出,精度影响所有有效位,对于 fixed 精度将影响小数位,对于科学表示法 scientific,精度影响底数小数位。

* 当默认表达形式整数位大于精度范围,或第一个非零数位于小数点后精度位以上,使用科学表示法。

五、设置输出流的宽度
1)使用 ios_base 的成员函数 width()
width() 获取输出流的输出宽度,当不能完整表示整数或带小数位的实数,则至少扩展到合理表达的宽度,包含有效的精度位,默认情况下返回 0,即没有限制宽度。
width(n) 设置输出流的输出宽度,仅影响下一次的输出。例如,我们准备输出 32bit 的十六进制数,包含 "0x" 前缀,总共需要 10 个位数的输出,使用 ios_base::width(10) 来设置输出宽度,并设置空缺位的填充字符为 '0',使用 basic_ios::fill('0'),为输出流传递操纵符 internal 按内部对齐方式将使基数修饰前缀和数值分别对齐到限制宽度区域的两侧,中间使用 '0' 字符填充。

2)使用操纵符 setw(n)
类似的操纵符还有控制浮点输出精度的 setprecision(n)。

六、操纵符 manipulator
1)操纵符的实现
重载流的 operator << 或者 operator >> 运算符,使之接受特定类型的非成员 / 静态成员函数,并代为访问该函数,称为流的操纵符。函数将实现为使用流的引用来访问流的成员函数和数据。以下是一个可用于操纵符的函数:

inline ios_base& __cdecl right(ios_base& _Iosbase)
        {       // set right in adjustfield
        _Iosbase.setf(ios_base::right, ios_base::adjustfield);
        return (_Iosbase);
        }

2)带参数的操纵符
普通的操纵符仅仅接受函数指针来实现 operator << 中的访问权转发。为了使获得转发的访问权的函数可能传递特定的参数,仅仅传递函数指针是行不通的,必须实现一类操纵符专用的类型模板以持有函数指针和参数,接受一个参数的操纵符函数将实例化一个携带函数指针和参数的对象,并重载使用该对象的 operator << 或者 operator >> 运算符。

一个带参数的操纵符:

_Smanip<streamsize> __cdecl setw(streamsize wide)
        {       // manipulator to set width
        return (_Smanip<streamsize>(&swfun, wide));
        }

为该操纵符重载流的输入输出运算符:

template<class _Elem, class _Traits, class _Arg> inline
        basic_istream<_Elem, _Traits>& __cdecl operator>>(
                basic_istream<_Elem, _Traits>& _Istr, const _Smanip<_Arg>& _Manip)
        {       // extract by calling function with input stream and argument
        (*_Manip._Pfun)(_Istr, _Manip._Manarg);
        return (_Istr);
        }

3)标准库中涉及一个参数的操纵符
        resetiosflags(f) 清除指定格式标志位
        setiosflags(f) 设置指定格式标志位
        setbase(n) 设置整数的基数
        setfill(c) 设置填充字符
        setprecision(n) 设置精度
        setw(n) 设置宽度

第四节、文件流和字符串流

一、流的层次结构简图

1)iostream 是同时具有读写能力的流,分别通过访问写缓冲区和读缓冲区完成
2)is_open() 检查文件流是否已打开
3)ios_base::ate 和 ios_base::app 文件流打开标志的区别
ate 仅在第一次读入时位于文件尾。
app 总是向尾部追加数据。
附带 _Nocreate 避免每次打开时均重新创建,并要求指定文件已打开。

二、使用全局计数器以确认当前初始化状态,对于需要确认其创建优先顺序的对象构造使用计数

三、字符串流 stringstream
stringstream 不依赖于文件和输入输出,以附加的 string 作为基点操作文本流,或者返回 string 类型。
iostream 是 stringstream 的基类,提供了丰富的格式控制、进制控制、浮点控制等操作,这些操作的实现是基于流技术的。通过字符串流附加字符串,执行一系列操作后再返回字符串,可以更灵活地,且相对 C 风格的字符串缓存操作更安全地实现字符格式化处理。

四、缓冲区
不同的流使用内存或者外设的形式是不同的,并且对于同一类流对象,允许更改缓冲区的实现也是很有帮助的。因此,缓冲区被实现为独立的 streambuf 类型,抽象了访问内存和外设的实际动作。
1)流缓冲区封装对象实现了分别指向输出流缓冲区和输入流缓冲区的两组指针,可以分别控制输出和输入
在输出流的基类中,ostream 使用成员函数 seekp() 来移动放置字符的位置,即 "seek put position"。

seekp(pos_type) 定位输出缓冲到指定位置
seekp(off_type, ios_base::seekdir) 根据偏移量和方向来定位输出缓冲的位置

* ios_base::seekdir 可传递三种取值:

static const _Seekdir beg = (_Seekdir)0;
static const _Seekdir cur = (_Seekdir)1;
static const _Seekdir end = (_Seekdir)2;

seekp() 在内部调用 streambuf 的 pubseekpos(_Pos, ios_base::out) 成员函数。
与之对应,seekg() 作为 istream 的成员函数,更改输入流的索引指针,在内部调用 streambuf 的 pubseekpos(_Pos, ios_base::in) 成员函数。

2)每个流对象均关联特定的流缓冲指针
3)流的索引指针定位操作,仅在该流关联的操作设备进行定位操作有意义时被使用,例如输出流可能被实现为每写入一次数据,数据将被立即刷新到标准输出,而不在缓冲区停留,在此类缓冲区上操作流的索引指针是没有意义的,并引发指向了无效元素位的 ios_base::failbit 异常
4)输入流操作

seekg(pos_type)
seekg(off_type, ios_base::seekdir)

putback(c) 将指定字符返回给输入流缓冲的当前位置,失败时设置 ios_base::badbit 异常
unget() 返回上次从输入流读取的字符,失败时设置 ios_base::badbit 异常
peek() 获取输入流的一个字符,且不从输入流移除
sync() 同步输入设备和输入流缓冲
5)ios 和缓冲区的基本交互

rdbuf() 取出和设置关联缓冲区
imbue() 浸染缓冲区的本地化现场
narrow(c, char_c) 使用当前本地化,将当前字符编码转换到 char 类型
widen(char) 使用当前本地化,从 char 类型转换到当前字符编码

对于后两项,最常见的应用情况之一是对宽字符集的换行和零尾的宽度处理,例如,仅使用 '\0' 明文字符串,使用 widen() 成员函数,方便地将常见的 ASCII 字符转换到当前本地化的编码。

五、缓冲区的模型

1)输入流缓冲区界面
egptr() 输入流缓冲区尾端
gptr() 当前元素索引
eback() 输入流缓冲区的前端
gbump(n) 改变缓冲区的元素索引
setg(beg, cur, end) 设置输入流缓冲区指向存储指针

2)输出流缓冲区界面
pbase() 输出流缓冲区的前端
pptr() 当前元素索引
epptr() 输出流缓冲区尾端
pbump(n) 改变缓冲区的元素索引
setp(beg, end) 设置输出流缓冲区指向存储指针

六、和 C 风格 IO 的同步
ios_base::sync_with_stdio(bool) 设置 C 和 C++ 库同步常规输入输出设备的使用,并可能因此损失部分性能。

[C++]STL map常用操作简介

 1。目录

  1. map简介
  2. map的功能
  3. 使用map
  4. map中插入元素
  5. 查找并获取map中的元素
  6. map中删除元素

2map简介

map是一类关联式容器。它的特点是增加和删除节点对迭代器的影响很小,除了那个操作节点,对其他的节点都没有什么影响。对于迭代器来说,可以修改实值,而不能修改key

3map的功能

  1. 自动建立Key value的对应。key value可以是任意你需要的类型。
  2. 根据key值快速查找记录,查找的复杂度基本是Log(N),如果有1000个记录,最多查找10次,1,000,000个记录,最多查找20次。
  3. 快速插入Key - Value 记录。
  4. 快速删除记录
  5. 根据Key 修改value记录。
  6. 遍历所有记录。

4。使用map

使用map得包含map类所在的头文件
#include <map> //
注意,STL头文件没有扩展名.h

map对象是模板类,需要关键字和存储对象两个模板参数:
std:map<int, string> personnel;
这样就定义了一个用int作为索引,并拥有相关联的指向string的指针.

为了使用方便,可以对模板类进行一下类型定义,

typedef map<int, CString> UDT_MAP_INT_CSTRING;
UDT_MAP_INT_CSTRING enumMap;

5。在map中插入元素

改变map中的条目非常简单,因为map类已经对[]操作符进行了重载

enumMap[1] = "One";
enumMap[2] = "Two";
.....

这样非常直观,但存在一个性能的问题。插入2,先在enumMap中查找主键为2的项,没发现,然后将一个新的对象插入enumMap,键是2,值是一个空字符串,插入完成后,将字符串赋为"Two"; 该方法会将每个值都赋为缺省值,然后再赋为显示的值,如果元素是类对象,则开销比较大。我们可以用以下方法来避免开销:

enumMap.insert(map<int, CString> :: value_type(2, "Two"))

6。查找并获取map中的元素

下标操作符给出了获得一个值的最简单方法:

CString tmp = enumMap[2];

但是,只有当map中有这个键的实例时才对,否则会自动插入一个实例,值为初始化值

我们可以使用Find()Count()方法来发现一个键是否存在。

查找map中是否包含某个关键字条目用find()方法,传入的参数是要查找的key,在这里需要提到的是begin()end()两个成员,分别代表map对象中第一个条目和最后一个条目,这两个数据的类型是iterator.

int nFindKey = 2;            //要查找的Key
//
定义一个条目变量(实际是指针)
UDT_MAP_INT_CSTRING::iterator it= enumMap.find(nFindKey);
if(it == enumMap.end()) {
    //
没找到
}
else {
    //
找到
}

通过map对象的方法获取的iterator数据类型是一个std::pair对象,包括两个数据 iterator->first iterator->second 分别代表关键字和存储的数据

7。从map中删除元素

移除某个map中某个条目用erase()

该成员方法的定义如下

  1. iterator erase(iterator it); //通过一个条目对象删除
  2. iterator erase(iterator first, iterator last);        //删除一个范围
  3. size_type erase(const Key& key); //通过关键字删除

clear()就相当于 enumMap.erase(enumMap.begin(), enumMap.end());

 

[计算几何]计算几何模板下载(二)


这个是2008年写的,先前那个是2007年写的  计算几何模板下载(一)  http://onchf.spaces.live.com/blog/cns!C1747339B0D46E11!285.entry
点击下载      计算几何_陈海丰(二).doc
 
计算几何模板目录
(1)几何公式    
(2)ComputationalGeometry2008  
(3)凸包(新)   
(4)hdu1589_最近最远点对  
(5)最小圆覆盖 包含点集所有点的最小圆的算法(暑假打印) 
(6)直线旋转_两凸包的最短距离(poj3608)  
(7)单位圆覆盖最多点(poj1981)
(8)经度纬度的应用(pku2587,pku3407) 
(9)判断球和立方体是否相交(hdoj2436)  
(10)判断两个凸包是否相交(cug1249) 
(11)判断两个多边形是否相似(PKU1931)  
(12)圆是否在凸多边形内(pku1584) 
(13)计算线段在多边形内的长度 
(14)pku1177_Picture_容斥原理 
(15)pku2002_3432_N个点最多组成多少个正方形(hao) 
(16)最小的矩形包含N个点中的M个(poj3681) 
(17)气球在三角形中的最大面积(pku1927)  
(18)两个圆相交的面积  
(19)长方体上一点到原点的距离(pku2977) 
(20)线段树+N个矩形覆盖的面积(poj3277)  
(21)两条线段最多接多少雨水(poj2826)  
(22)最短路径+角度旋转  
(23)pku3253_堆_哈夫曼树  
(24)线段覆盖(poj2074 Line of Sight)  
(25)四面体的体积(pku2208) 
(26)三维点积叉积的应用(三维凸包的面积2974)  
(27)反射(hdu2355) 
(28)N个点最多确定多少互不平行的直线(poj3668)
(29)求两个凸多边形的交集面积
(30)房间找一位置可看到所有角落
(31)两个简单多边形的交的面积
(32)多边形费马点
(33)最近点对问题(贪心算法) 
(34)奶牛的位置(离其他点的倒数和最小)
(35)双人游戏(Hotter) 
(36)Map(包含所有矩形的最小个数) 
(37)gunman(存在空间线段穿过所有的平面)
 

[计算几何]包含K个点的最小扇形(HDU2469)

http://acm.hdu.edu.cn/showproblem.php?pid=2469 

Fire-Control System

Time Limit: 8000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Problem Description

A new mighty weapon has just been developed, which is so powerful that it can attack a sector of indefinite size, as long as the center of the circle containing the sector is the location of the weapon. We are interested in developing a fire-control system that calculates firing-solutions automatically.
The following example gives an example of a firing solution:
Figure 1

Here the firing region is the sector "ABC" that covers six points: A, B, C, D, E, H. You may further assume that the weapon is always located at point (0, 0), no targets will be on the point (0, 0) and the coordinates of the targets will be distinct.
A firing solution is called effective if and only if it covers a minimum of K points
out of N given points (targets) on the two-dimensional Cartesian plane. Furthermore,since the cost of a particular fire solution is in direct proportion to the size of the area it covers, a firing could be quite costly; thus we are only interested in the optimal firing solution with the minimum cost.

Input

There are multiple test cases in the input file.
Each test case starts with two non-negative integers, N and K
(1 ≤ N ≤ 5000 , K ≤ N ), followed by N lines each containing two integers, X, and Y, describing the distinct location of one target. It is guaranteed that the absolute value of any integer does not exceed 1000.
Two successive test cases are separated by a blank line. A case with N = 0 and K = 0 indicates the end of the input file, and should not be processed by your program.

Output

For each test case, please print the required size (to two decimal places), in the
format as indicated in the sample output.

Sample Input

3 1
0 1
1 0
-5 -6
3 2
0 2
2 0
-5 -6
0 0

Sample Output

Case #1: 0.00
Case #2: 3.14
#include <math.h>
#include <stdio.h>
#include <stdlib.h>

#define sqr(x) ((x) * (x))
#define pi 3.1415926535897932384626433832795

struct point
{
    int x, y;
    double slope;
};

int cmp(const void *a, const void *b)
{
    point *c = (point *)a;
    point *d = (point *)b;
    if(c->slope < d->slope) return -1;
    return 1;
}

int cmpint(const void *a, const void *b)
{
    if(*(int *)a < *(int *)b) return -1;
    return 1;
}

int main()
{
    point p[5005];
    int r[5005], tr[5005], test = 1;
    int n, k, i, j, cnt, s, e;
    double min_angle, angle, area, min_area;
    while(scanf("%d%d", &n, &k) != EOF)
    {
        if(n == 0 && k == 0) break;
        for(i = 0;i < n;i++)
        {
            scanf("%d%d", &p[i].x, &p[i].y);
            p[i].slope = atan2(p[i].y, p[i].x);
            if(p[i].slope < 0) p[i].slope += 2 * pi;
        }
        qsort(p, n, sizeof(p[0]), cmp);
        for(i = 0;i < n;i++)
            r[i] = tr[i] =  sqr(p[i].x) + sqr(p[i].y);
        qsort(r, n, sizeof(r[0]), cmpint);
        int rn = 1;
        for(i = 1;i < n;i++)
            if(r[i] != r[rn - 1]) r[rn++] = r[i];
        min_area = 1e250;
        for(i = rn - 1;i >= 0;i--)
        {
            min_angle = 100;
            cnt = 0;
            for(j = 0;j < n;j++)
            {
                if(tr[j] <= r[i])
                {
                     if(cnt == 0) s = e = j;
                     cnt++;
                }
            }
            if(cnt < k) break;
            cnt = 1;
            while(e < n)
            {
                while(cnt < k) 
                {
                    s++;
                    if(tr[s % n] <= r[i]) cnt++;
                }
                if(s >= n) angle = 2 * pi - fabs(p[s % n].slope -  p[e].slope);
                else angle = p[s].slope - p[e].slope;
                if(angle < min_angle) min_angle = angle;
                cnt--;
                e++;
                while(tr[e] > r[i] && e < n) e++;  
            }
            area = min_angle * r[i] / 2;    
            if(area < min_area) min_area = area;
        }
        printf("Case #%d: %.2lf\n", test++, min_area);
    }
    return 0;
}

[计算几何]圆上找一点使看到圆内凸包的角度最大(ncpc2008)

1

Hard Evidence
The young reporter Janne is planning to take a photo of a secret
government installation. He needs to obtain evidence of the
many serious crimes against good sense that are being committed
there, so as to create a scandal and possibly win a Pulitzer.
Unfortunately, the base is surrounded by a high fence with high
voltage wires running around. Janne does not want to risk being
electrocuted, so he wants to take a photo from outside the fence.
He can bring a tripod as high as the fence to take a photo, so if
he wants he can stand right beside the fence and take his picture.
The secret installation is a convex polygon. The fence has a form
of a circle. Of course Janne wants to make a photo with maximal possible detail level.
The detail level of the photo depends on the view angle of the base at the point from
which the photo is taken. Therefore he wants to nd a point to maximize this angle.
Input speci cations
The rst line of the input le contains two integer numbers: n and r | the number of
vertices of the polygon and the radius of the fence (3 n 200, 1 r 1000 ). The
following n lines contain two real numbers each | the coordinates of the vertices of the
polygon listed in counterclockwise order. It is guaranteed that all vertices of the polygon
are strictly inside the fence circle, and that the polygon is convex. The center of the fence
circle is located at the origin, (0; 0).
Output speci cations
Output the maximal view angle a for the photo (0 a < 2). Any answer with either
absolute or relative error smaller than 106 is acceptable.
Sample input

1 4 2
-1.0 -1.0
1.0 -1.0
1.0 1.0
-1.0 1.0

Sample output 1


1.5707963268

#include <math.h>
#include <stdio.h>

#define eps 1e-6
#define pi acos(-1.0)
#define max(a, b) ((a) > (b) ? (a) : (b))

double GetViewAngle(double px1, double py1, double px2, double py2, double a, double r)
{
	double qx = cos(a)*r, qy = sin(a) * r;
	double vx1 = qx - px1, vy1 = qy - py1, vx2 = qx - px2, vy2 = qy - py2;
	double d = (vx1 * vx2 + vy1 * vy2) / (sqrt(vx1 * vx1 + vy1 * vy1) * sqrt(vx2 * vx2 + vy2 * vy2));
	double angle = acos(d);
	return angle;
}

void QuadraticEquation(double a, double b, double c, double &res1, double &res2)
{
	double d = b * b - 4 * a * c;
	if (d < 0) return ;
	d = sqrt(d);
	res1 = (-b + d) / (2 * a);
	res2 = (-b - d) / (2 * a);
	return ;
}

int main()
{
	freopen("evidence.in", "r", stdin);
	freopen("evid11.out", "w", stdout);
	int n;
	double r, res1, res2;
	double x1, x2, va1, va2;
	double lo, hi, angle, dif;
	double px1, py1, px2, py2;
	double x[205], y[205];
	double bestAngle, bestX, bestY;
	double start[205], stop[205];
	double dx, dy, c, a, b;
	while(scanf("%d%lf", &n, &r) != EOF)
	{
		for(int i = 0;i < n;i++)
		{
			scanf("%lf%lf", &x[i], &y[i]);
		}
		bestAngle = 0, bestX = 0, bestY = 0;
		for(int i = 0;i < n;i++)
		{
			int j = (i + 1) % n;
			dx = x[j] - x[i], dy = y[j] - y[i];
			c = x[i] * x[i] + y[i] * y[i] - r * r;
			a = dx * dx + dy * dy, b = 2 * (dx * x[i] + dy * y[i]);
			QuadraticEquation(a, b, c, res1, res2);
			px1 = x[i] + res1 * dx, py1 = y[i] + res1 * dy;
			px2 = x[i] + res2 * dx, py2 = y[i] + res2 * dy;
			start[i] = atan2(py2, px2);
			stop[i] = atan2(py1, px1);
		}
		for(int i = 0;i < n;i++)
		{
			int t = i;
			while(1)
			{
				lo = start[t], hi = stop[i];
				if(hi < lo) hi += 2 * pi;
				angle = 0;
				while(hi - lo > 1e-6)
				{
					x1 = (hi - lo) / 3 + lo;
					x2 = (hi - lo) / 3 * 2 + lo;
					va1 = GetViewAngle(x[i], y[i], x[(t + 1)%n], y[(t + 1)%n], x1, r);
					va2 = GetViewAngle(x[i], y[i], x[(t + 1)%n], y[(t + 1)%n], x2, r);
					angle = max(va1, va2);
					if (va1 > va2) hi = x2;
					else lo = x1;
				}
				if (angle > bestAngle)
				{
					bestAngle = angle;
					bestX = cos(lo) * r;
					bestY = sin(lo) * r;
				}
				dif = start[(t + 1) % n] - stop[i];
				if (dif > pi) dif -= 2 * pi;
				if (dif < -pi) dif += 2 * pi;
				if (dif > 0) break;
				t = (t + 1) % n;
			}
		}
		printf("%.10lf\n", bestAngle);
	}
	return 0;			
}

中国科学院研究生院计算机科学与技术课程设置一览表

& 查看学科专家组信息,请点击此处。

  查看课程大纲内容,请点击“课程名称”下的相应课程名称链接;若该课程无链接,则表示该课程无大纲。

一级学科课程设置一览表
计算机科学与技术(0812)
课程类型 课程设置码 课程名称 名称(英文) 学时/分
学科基础课 S081200J01 数理逻辑 Mathematical Logic 60/3
S081200J02 组合数学 Combinatorial Mathematics 60/3
S081200J03 计算机算法设计与分析 The Design and Analysis of Computer Algorithms 60/3
S081200J04 排队论 Queueing Theory 60/3
S081200J05 高级人工智能 Advanced Artificial Intelligence 60/3
S081200J06 计算机体系结构 Computer System Architecture 60/3
S081200J07 软件开发和程序设计方法学 Software Development and Programming Methodology 60/3
S081200J08 高级计算机网络 Advanced Computer Networks 60/3
S081200J09 计算机视觉与图像理解 Computer Vision and Image Understanding 60/3
S081200J10 计算机通信网络安全 Computer Communication Network Security 60/3
S081200J11 高级软件工程 Advanced Course on Software Engineering 60/3
S081200J12 人机交互界面理论与技术 Principle of Human-Computer Interface 60/3
S081200J13 高性能计算机系统 High Performance Computer Systems 60/3
学科综合课 S081200Z01 先进计算机和软件技术系统讲座 Topics in advanced computer and software technology 30/1

二级学科课程设置一览表
计算机系统结构(081201)
课程类型 课程设置码 课程名称 名称(英文) 学时/分
专业基础课 S081201J01 分布式多媒体计算机系统 Distributed Multimedia Computer Systems 60/3
S081201J02 计算机系统性能评价 Performance Evaluation of Computer Systems 60/3
S081201J03 编译程序高级教程 Compilers: An Advanced Course 60/3
S081201J04 分布式操作系统 Distributed Operating Systems 60/3
S081201J05 并行处理 Parallel Process 60/3
S081201J06 VLSI测试与可测性设计 Testing and Testable Design of VLSI Systems 60/3
S081201J07 计算机网络设计与性能分析 Computer Network Design and performance Analysis 60/3
S081201J08 数字集成系统设计 Design of Digital Integrated System 60/3
S081201J09 计算机网络体系结构 Computer Networks Architecture 60/3
S081201J10 处理器设计实用教程 Practical Course on CPU Design 60/3
S081201J11 计算机网络 Computer Networks 60/3
S081201J12 数字系统的故障诊断与容错设计 Diagnosis and Fault-Tolerant Design of Digital Systems 60/3
S081201J13 高级通信原理 Advanced Telecommunications Principle 60/3
S081201J14 数字图像处理 Digital Image Processing 60/3
S081201J15 现代数字信号处理 Advanced Digital Signal Processing 60/3
S081201J16 数字系统设计自动化 Automatic Design for Digital System 60/3
专业课 S081201Z01 宽带网络技术 Broadband Network Technology 60/3
S081201Z02 VLSI/SOC可测性设计 Design for Testability of VLSI/SOC 60/3
S081201Z03 操作系统高级教程 Advanced Course of Operating Systems 60/3
S081201Z04 网络分布计算理论和技术 Theory and Technology of Network and Distributed Computing 60/3
S081201Z05 量子信息处理 Quantum Information Processing 40/2

二级学科课程设置一览表
计算机软件与理论(081202)
课程类型 课程设置码 课程名称 名称(英文) 学时/分
专业基础课 S081202J01 可计算性与计算复杂性 Computability and Complexity of Computing 60/3
S081202J02 形式语言与自动机理论 Formal language and Automata theory 60/3
S081202J03 编译程序高级教程 Compilers: An Advanced Course 60/3
S081202J04 数据库技术 Database Technology 60/3
S081202J05 分布式操作系统 Distributed Operating Systems 60/3
S081202J06 软件理论基础 The Foundations of Software Theory 60/3
S081202J07 软件工程 Software Engineering 60/3
S081202J08 软件测试与软件可靠性 Software Testing and Software Reliability 40/2
S081202J09 程序设计语言理论 Theory of Programming Languages 60/3
S081202J10 并行处理 Parallel Process 60/3
S081202J11 信息论与编码 Information Theory and Coding 60/3
S081202J12 人工智能原理 The Principles of Artificial Intelligence 60/3
S081202J13 形式语义学引论 Introduction to Formal Semantics 60/3
S081202J14 数值分析 Numerical Analysis 60/3
S081202J15 分布式多媒体计算机系统 Distributed Multimedia Computer Systems 60/3
S081202J16 计算语言学 Computational Linguistics 40/2
S081202J17 现代密码学——理论与实践 Contemporary Cryptography——Theory and Practice 60/3
S081202J18 代数基础与有限域 Algebraic Foundations and Finite Fields 60/3
专业课 S081202Z01 程序的形式验证 Program Formal Validation 60/3
S081202Z02 统计学方法及其工程应用 Statistical Methods for Engineers 60/3
S081202Z03 操作系统高级教程 Advanced Course of Operating Systems 60/3
S081202Z04 进程代数 Process Algebra 60/3
S081202Z05 软件体系结构 Software Architecture 60/3
S081202Z06 网络分布计算理论和技术 Theory and Technology of Network and Distributed Computing 60/3
S081202Z07 多元统计分析 Multivariate Analysis 60/3
S081202Z08 实时系统理论与方法 Theory and Methods of Real-time Systems 60/3
S081202Z09 安全信息系统概论 Introdution to Information System Security 60/3
S081202Z10 计算数论 Computational Number Theory 60/3
S081202Z11 理论密码学 Theoretical Cryptography 60/3
S081202Z12 量子信息处理 Quantum Information Processing 40/2

二级学科课程设置一览表
计算机应用技术(081203)
课程类型 课程设置码 课程名称 名称(英文) 学时/分
专业基础课 S081203J01 人工智能原理 The Principles of Artificial Intelligence 60/3
S081203J02 神经计算 Neural Computing 60/3
S081203J03 分布式数据库系统及其应用 Distributed Database System & Application 60/3
S081203J04 数据库技术 Database Technology 60/3
S081203J05 工程数据库 Engineering Data Base 60/3
S081203J06 应用软件开发工具 Computer aided tools for system modeling & programming 40/2
S081203J07 计算机图形学 Computer Graphics 60/3
S081203J08 信息工程 Information Engineering 40/2
S081203J09 数字系统设计自动化 Automatic Design for Digital System 60/3
S081203J10 模糊数学及计算机应用 Fuzzy Mathematics and Application to Computer Sciences 60/3
S081203J11 计算机网络体系结构 Computer Networks Architecture 60/3
S081203J12 计算机网络 Computer Networks 60/3
S081203J13 多媒体计算机技术 Multimedia Computer Technology 60/3
S081203J14 模式识别与智能系统 Pattern Recognition and Intelligence System 60/3
S081203J15 高级通信原理 Advanced Telecommunications Principle 60/3
S081203J16 数字图像处理 Digital Image Processing 60/3
S081203J17 现代数字信号处理 Advanced Digital Signal Processing 60/3
S081203J18 语音交互技术基本原理 Fundamental of Speech Interaction Technology 40/2
S081203J19 数字系统的故障诊断与容错设计 Diagnosis and Fault-Tolerant Design of Digital Systems 60/3
S081203J20 计算机网络设计与性能分析 Computer Network Design and performance Analysis 60/3
S081203J21 数值分析 Numerical Analysis 60/3
专业课 S081203Z01 分布系统集成与构件技术 Distributed System Integration and Component Technology 60/3
S081203Z02 嵌入式计算机系统设计原理 Principles of Embedded Computing Systems 40/2
S081203Z03 面向对象软件技术 Object-Oriented Software Technology 60/3
S081203Z04 纠错编码 Error-Correcting Codes 40/2
S081203Z05 信息安全工程技术 Information Security Engineering 60/3
S081203Z06 自然语言理解 Natural Language Understanding 60/3

[计算几何]两个圆相交的面积

#include<math.h>  
#include<stdio.h>  

#define pi acos(-1.0)
#define sqr(x) ((x) * (x))
#define dis2(a, b) (sqrt(sqr(a.x - b.x) + sqr(a.y - b.y)))

struct point
{
	double x, y;
};

struct circle
{
	point c;
	double r;
};

double IntersectionArea(circle cir1, circle cir2)
{  
	double A1, A2, d, ang1, ang2;
	circle ctmp;
	if (cir1.r < cir2.r)  
    {  
		ctmp = cir1;
		cir1 = cir2;
		cir2 = ctmp;	
    }
    double ret = 0;  
    A1 = pi * sqr(cir1.r);  
    A2 = pi * sqr(cir2.r);  
    d = dis2(cir1.c, cir2.c);
      
    if (d >= cir1.r + cir2.r) return 0;  
    if (d <= cir1.r - cir2.r) return A2;  
       
    ang1 = acos((sqr(cir1.r)+ sqr(d) - sqr(cir2.r)) / 2 / cir1.r/ d);  
    ang2 = acos((sqr(cir2.r)+ sqr(d) - sqr(cir1.r)) / 2 / cir2.r/ d);  
    
    ret -= sqr(cir1.r) * ang1 - sqr(cir1.r) * sin(ang1) * cos(ang1);
    ret -= sqr(cir2.r) * ang2 - sqr(cir2.r) * sin(ang2) * cos(ang2); 
    return -ret;
} 

int main()
{
	int test;
	circle cir1, cir2;
	scanf("%d", &test);
	while(test--)
	{
		scanf("%lf%lf%lf", &cir1.c.x, &cir1.c.y, &cir1.r);
		scanf("%lf%lf%lf", &cir2.c.x, &cir2.c.y, &cir2.r);
        printf("%.3lf\n", IntersectionArea(cir1, cir2));
	}
	return 0;
}

[计算几何]判断两个多边形是否相似(pku1931)

http://acm.pku.edu.cn/JudgeOnline/problem?id=1931 
/*
http://acm.pku.edu.cn/JudgeOnline/problem?id=1931

Biometrics

Description

Recently, the term Biometrics been used to refer to the emerging field of technology devoted to identification of individuals using biological traits, such as those based on retinal or iris scanning, fingerprints, or face recognition. 
A simple biometric system translates a human image into a polygon by considering certain features (eyes, nose, ears, etc.) to be vertices and connecting them with line segments. The polygon has distinct vertices but may be degenerate in that the line segments could intersect. Because these polygons are generally created from remote images, there is some uncertainty as to their scale and rotation. Your job is to determine whether or not two polygons are similar; that is, can they be made equal by repositioning, rotating and magnifying them?
Input

Input consists of several test cases. Each test case consists of three lines containing: 

f, the number of features 

f coordinate pairs giving the vertices of the first polygon 

f coordinate pairs giving the vertices of the second polygon 

The vertices for both polygons correspond to the same set of features in the same order; for example, right ear tip, chin cleft, right eye, nose, left eye, left ear tip, space between front teeth. Each polygon has f vertices; each vertex is given as an x and y coordinate pair. There are at least three and no more than ten features. Coordinates are integers between -1000 and 1000. A line containing 0 follows the last test case. 
Output

For each case, output a line "similar" or "dissimilar" as appropriate. The two polygons are similar if, after some combination of translation, rotation, and scaling (but not reflection) both vertices corresponding to each feature are in the same position. 
Sample Input

4
0 0 0 1 1 1 1 0
0 1 1 0 0 -1 -1 0
3
0 0 10 0 10 10
0 0 -10 0 -10 10
3
0 0 10 10 20 20
0 0 11 11 22 22
3
0 0 10 10 20 20
0 0 11 11 20 20
0

Sample Output

similar
dissimilar
similar
dissimilar

Source
Waterloo local 2003.09.27
*/
/*
判断两多边形相似,只要对应边成比例,且对应的角相当,
由于这题多边形可能存在边的自交,所以还要加上每个角
的转向相同
*/

#include <math.h>
#include <stdio.h>

#define eps 1e-6
#define sqr(x) ((x) * (x))
#define same(a, b) (fabs((a) - (b)) < eps) 
#define dis2(a, b) (sqrt(sqr(a.x - b.x) + sqr(a.y - b.y)))

struct point 
{
	double x, y;
	point operator-(point &b)
	{
		point c;
		c.x = x - b.x;
		c.y = y - b.y;
		return c;
	}
};

double dot(point a, point b)
{
	return a.x * b.x + a.y * b.y;
}

double cross(point a, point b)
{
	return a.x * b.y - a.y * b.x;
}

double get_anlge(point p1, point p2, point p3)
{
	//不需要求反余弦,点击相当,反余弦相等,避免使用反三角函数
	return dot(p1 - p2, p3 - p2) / dis2(p1, p2) / dis2(p2, p3);
}

int get_dir(point p1, point p2, point p3)
{
	//根据三点得到转向
	double t1 = cross(p2 - p1, p3 - p2);
	if(fabs(t1) < eps) return 1;
	if(t1 < 0) return 2;
	else return 3;	
}

int slove(double ang1[], double ang2[], double len1[], double len2[], int dir1[], int dir2[], int n)
{
	/*由于题目已经告诉了对应点的匹配顺序,所以只需要从
	0,开始匹配,如果没有告诉对应的匹配顺序,就还有枚举
	匹配对应边*/
	//int k;
	/*for(int i = 0;i < n;i++)
	{
		for(int j = 0;j < n;j++)
		{
			//第i条边和第j条边相对应*/
			int s, t, k;
			s = 0;
			t = 0;
			for(k = 0;k < n;k++)
			{
				if(!same(ang1[s], ang2[t]) || !same(len1[s], len2[t]) || dir1[s] != dir2[t]) break;
				s++;
				t++;
				s %= n;
				t %= n;
			} 
			if(k == n) return 1;
		/*}
	}*/
	return 0;
}

double polygonArea(point p[], int n)
{
    //已知多边形各顶点的坐标,求其面积
    double area = 0.0;
    for(int i = 1;i <= n;i++)
        area += (p[i - 1].x * p[i % n].y - p[i % n].x * p[i - 1].y);  
    return area;   
}

int main()
{
	int n, similar;
	point p1[20], p2[20];
	double max1, max2;
	double ang1[20], ang2[20], len1[20], len2[20];
	int dir1[20], dir2[20];
	while(scanf("%d", &n) && n)
	{
		for(int i = 0;i < n;i++)
		{
			scanf("%lf%lf", &p1[i].x, &p1[i].y);
		}
		for(int i = 0;i < n;i++)
		{
			scanf("%lf%lf", &p2[i].x, &p2[i].y);
		}
		ang1[0] = get_anlge(p1[n - 1], p1[0], p1[1]);
		ang2[0] = get_anlge(p2[n - 1], p2[0], p2[1]);
		dir1[0] = get_dir(p1[n - 1], p1[0], p1[1]);
		dir2[0] = get_dir(p2[n - 1], p2[0], p2[1]);
		for(int i = 1;i < n;i++)
		{
			ang1[i] = get_anlge(p1[i - 1], p1[i], p1[(i + 1) % n]);
			ang2[i] = get_anlge(p2[i - 1], p2[i], p2[(i + 1) % n]);
			dir1[i] = get_dir(p1[i - 1], p1[i], p1[(i + 1) % n]);
			dir2[i] = get_dir(p2[i - 1], p2[i], p2[(i + 1) % n]);
		}
		max1 = -1, max2 = -1;
		for(int i = 0;i < n;i++)
		{
			len1[i] = dis2(p1[i], p1[(i + 1) % n]);
			if(len1[i] > max1) max1 = len1[i];
			len2[i] = dis2(p2[i], p2[(i + 1) % n]);
			if(len2[i] > max2) max2 = len2[i];
		}
		for(int i = 0;i < n;i++)
		{
			len1[i] /= max1;
			len2[i] /= max2;
		}
		if(slove(ang1, ang2, len1, len2, dir1, dir2, n)) printf("similar\n");
		else printf("dissimilar\n");		
	}
	return 0;
}

#include <stdio.h>
#include <math.h>

typedef struct {
  int x, y;
} Point;

/* counterclockwise, clockwise, or undefined */
enum {CCW, CW, CNEITHER};

int ccw(Point a, Point b, Point c)
{
  int dx1 = b.x - a.x;
  int dx2 = c.x - b.x;
  int dy1 = b.y - a.y;
  int dy2 = c.y - b.y;
  int t1 = dy2 * dx1;
  int t2 = dy1 * dx2;

  if (t1 == t2) {
    if (dx1 * dx2 < 0 || dy1 * dy2 < 0) {
      if (dx1*dx1 + dy1*dy1 >= dx2*dx2 + dy2*dy2) {
        return CNEITHER;
      } else {
        return CW;
      }
    } else {
      return CCW;
    }
  } else if (t1 > t2) {
    return CCW;
  } else {
    return CW;
  }
}

void read_poly(int n, Point *poly)
{
  int i;
  
  for (i = 0; i < n; i++) {
    scanf("%d %d", &(poly[i].x), &(poly[i].y));
  }
  poly[n] = poly[0];
  poly[n+1] = poly[1];
}

/* Note: we are really computing the cosine of the angle */
void compute(int n, Point *poly, double *angle, int *orient, double *dist)
{
  int dx1, dy1, dx2, dy2;
  int i;
  
  for (i = 0; i < n; i++) {
    /* i-th angle is angle formed by points i, i+1, i+2 */
    dx1 = poly[i].x - poly[i+1].x;  dy1 = poly[i].y - poly[i+1].y;
    dx2 = poly[i+2].x - poly[i+1].x; dy2 = poly[i+2].y - poly[i+1].y;
    angle[i] = (dx1*dx2+dy1*dy2)/sqrt(dx1*dx1+dy1*dy1)/sqrt(dx2*dx2+dy2*dy2);
    orient[i] = ccw(poly[i], poly[i+1], poly[i+2]);
    dist[i] = sqrt((poly[i+1].x-poly[i].x)*(poly[i+1].x-poly[i].x) +
      (poly[i+1].y-poly[i].y)*(poly[i+1].y-poly[i].y));
  }
}

int main(void)
{
  Point poly1[12], poly2[12];
  double angle1[10], angle2[10];
  int orient1[10], orient2[10];
  double dist1[10], dist2[10], ratio;
  int n, i;
  int similar;

  while (scanf("%d", &n) != EOF && n > 0) {
    read_poly(n, poly1);
    read_poly(n, poly2);

    compute(n, poly1, angle1, orient1, dist1);
    compute(n, poly2, angle2, orient2, dist2);
    ratio = dist2[0]/dist1[0];

    similar = 1;
    for (i = 0; i < n && similar; i++) {
      similar = (orient1[i] == orient2[i] && 
		 fabs(angle1[i]-angle2[i]) < 1e-8 &&
		 fabs(dist1[i]*ratio-dist2[i]) < 1e-8);
      
    }

    printf("%s\n", (similar) ? "similar" : "dissimilar");
  }
  
  return 0;
}

[计算几何]最短路径+角度旋转(pku3072)

http://acm.pku.edu.cn/JudgeOnline/problem?id=3072 
注意细节,没有啥好说的
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define pi acos(-1.0)
#define eps 1e-6
#define inf 0x7fffffff
#define sqr(x) ((x) * (x))
#define dis2(a, b) sqrt(sqr((double)a.x - b.x) + sqr((double)a.y - b.y))

int f[30];
double ans;

struct point
{
	int x, y;
	void input()
	{
		scanf("%d%d", &x, &y);
	}
};
point p[30];

double get_dis(const double ang, point p1, point p2, const int R, double &new_ang)
{
	double d = dis2(p1, p2);
	if(d > R) return -1;
	double t = atan2(p2.y - p1.y, p2.x - p1.x);
	if(t < 0) t += 2 * pi;
	new_ang = t * 180 / pi;
	double a = fabs(ang - new_ang);
	if(a > 180) a = 360 - a;
	return d + a;
}

void dfs(int x, const int n, double dis, double ang, const int R)
{
	if(dis > ans) return;//这句话忘加,tle 
	if(x == n - 1) 
	{
		if(dis < ans) ans = dis;
		return ;
	}
	double d, new_ang;
	for(int i = 0;i < n;i++)
	{
		if(f[i] == 0)
		{
			d = get_dis(ang, p[x], p[i], R, new_ang);
			if(fabs(d + 1) < eps) continue;
			f[i] = 1;
			dfs(i, n, dis + d, new_ang, R);	
			f[i] = 0;
		}
	}
}

int main()
{
	int R, n;
	double d, ang;
	while(scanf("%d%d", &R, &n) != EOF)
	{
		if(R == -1 && n == -1) break;
		for(int i = 0;i < n;i++)
			p[i].input();
		memset(f, 0, sizeof(f));
		ans = 1e250;
		double t = atan2(p[n - 1].y - p[0].y, p[n - 1].x - p[0].x);
		if(t < 0) t += 2 * pi;
		ang = t * 180 / pi;
		f[0] = 1;
		dfs(0, n, 0, ang, R);
		f[0] = 0;
		if(ans > 1e200) printf("impossible\n");
		else printf("%.0lf\n", ans);	
	}
	return 0;	
}

[计算几何]旋转+三角形外接圆(pku2957)

http://acm.pku.edu.cn/JudgeOnline/problem?id=2957 
/*
将第一点旋转a1度(旋转半径为r1即p1到原点的距离)
再将第二个点旋转a2度(旋转半径为r2即p2到原点的距离) 
最后三点都在同一个圆上,这个圆即为M在p3时绕P旋转的
所在轨道(圆周运动),再通过这三点求外接圆,得到的圆心
即为在第三时刻p的位置坐标圆心到原点的距离即为p到s的距离
*/
#include <math.h>
#include <stdio.h>

#define pi acos(-1.0)
#define sqr(x) ((x) * (x))
#define triArea(a, b, c) (fabs(multi(a, b, c) / 2))
#define dis2(a, b) sqrt(sqr(a.x - b.x) + sqr(a.y - b.y))
#define multi(a, b, c) ((b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y))

struct point
{
	double x, y;
	void input(){scanf("%lf%lf", &x, &y);}
	double dis2_or(){return sqrt(sqr(x) + sqr(y));}
};

struct circle
{
	point center;
	double r;
};

circle circumcircleOfTriangle(point t0, point t1, point t2)
{
    //三角形的外接圆
    circle tmp;
    double a, b, c, c1, c2;
    double xA, yA, xB, yB, xC, yC;
    a = dis2(t0, t1);
    b = dis2(t1, t2);
    c = dis2(t2, t0);
    //根据S = a * b * c / R / 4;求半径R 
    tmp.r = a * b * c / triArea(t0, t1, t2) / 4;
    
    xA = t0.x; yA = t0.y;
    xB = t1.x; yB = t1.y;
    xC = t2.x; yC = t2.y;
    c1 = (xA * xA + yA * yA - xB * xB - yB * yB) / 2;
    c2 = (xA * xA + yA * yA - xC * xC - yC * yC) / 2;
    
    tmp.center.x = (c1 * (yA - yC) - c2 * (yA - yB)) / 
		((xA - xB) * (yA - yC) - (xA - xC) * (yA - yB)); 
    tmp.center.y = (c1 * (xA - xC) - c2 * (xA - xB)) / 
		((yA - yB) * (xA - xC) - (yA - yC) * (xA - xB)); 
    return tmp;     
}

int main()
{
	int T, k1, k2;
	circle ci;
	point p1, p2, p3, p1_, p2_;
	double a1, a2, r1, r2;
	while(scanf("%d%d%d", &T, &k1, &k2) != EOF)
	{
		if(T == 0 && k1 == 0 && k2 == 0) break;
		p1.input();
		p2.input();
		p3.input();
		a1 = atan2(p1.y, p1.x) + 2* pi * ((double)k1 + k2) / T;
		a2 = atan2(p2.y, p2.x) + 2 * pi * (double)k2 / T;
		r1 = p1.dis2_or();
		r2 = p2.dis2_or();
		p1_.x = r1 * cos(a1);
		p1_.y = r1 * sin(a1);
		p2_.x = r2 * cos(a2);
		p2_.y = r2 * sin(a2);
		ci = circumcircleOfTriangle(p1_, p2_, p3);
		printf("%.0lf\n", ci.center.dis2_or());		
	}
	return 0;
}

[计算几何]经度纬度的应用(pku2587,pku3407)

 

http://acm.pku.edu.cn/JudgeOnline/problem?id=2587
http://acm.pku.edu.cn/JudgeOnline/problem?id=3407

/*
Brookebond s'en va en guerre...
Description
Famous military leader marshal Brookebond who has never lost a battle
 (truth to be told, he has never won one either) is sincerely convinced 
 that all military operations can be planned on the globe. Let’s not reveal
  the depth of his misconceptions to the poor marshal. Instead, let’s help
   him by writing a program to compute the distance between two points on the
    surface of the Earth given in the geographic coordinates. An order from
	 the marshal Brookebond declares the Earth to be a perfect sphere having
	  radius of 6370 kilometers. And the orders, as we all know, are not to
	   be discussed…
Geographic latitude and longitude are measured in degrees and minutes with the
 accuracy to one minute (one degree containing 60 minutes, of course). The
  latitude is measured from 90 degrees of northern latitude (N) for the North
   Pole to 90 degrees of southern latitude (S) for the South Pole; the latitude
    of any point on the equator is 0 degrees (N or S, does not matter). The
	 longitude of is measured from 180 degrees of eastern longitude (E) to
	  180 degrees of western longitude (W); for point on meridians with 
	  longitude 180 or 0, E and W are equivalent.
Input
The first and second lines of the input contain the coordinates (latitude 
and longitude) of one point each. The designation of a latitude contains 
two integers (degrees and minutes) and a letter N or S. Similarly, the 
designation of a longitude contains two integers (degrees and minutes) 
and a letter E or W. Adjacent values on a line are separated by one or 
more spaces.
Output
The first and only line of the output must contain the distance
 (in kilometers) between the points from the input file with 
 the precision of 1 meter.
Sample Input

55 0 N 40 0 E
59 0 N 49 30 E
Sample Output

725.979

假设地球是球体, 
设地球上某点的经度为lambda,纬度为phi, 
则这点的空间坐标是 
x=cos(phi)*cos(lambda) 
y=cos(phi)*sin(lambda) 
z=sin(phi) 
设地球上两点的空间坐标分别为(x1,y1,z1),(x2,y2,z2) 
直线距离即为R*sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(z2-z1)*(z2-z1)),
则它们的夹角为 
A = acos(x1 * x2 + y1 * y2 + z1 * z2),
则两地距离为 A * R,其中R为地球平均半径6371 

这里坐标都要乘以半径R,但由于是求角度,所以统一都没有乘 
注意这里还要判断坐标的正负和经度纬度的规定有关 

pku_3407

#include <stdio.h>
#include <math.h>

const double pi = acos(-1.0);

struct TPoint
{
   double x, y, z;
};
 
int main()
{
    double w1, wm1, j1, jm1, wd1, wd2;
    double w2, wm2, j2, jm2, jd1, jd2;
    TPoint p1, p2;
    char chr1, chr2;
    while(scanf("%lf%lf ", &w1, &wm1) != EOF){
        scanf("%c ", &chr1);
        scanf("%lf %lf %c", &j1, &jm1, &chr2);
        wd1 = (w1 + wm1 / 60) * pi / 180;
        jd1 = (j1 + jm1 / 60) * pi / 180;
        if(chr1 == 'S') wd1 *= -1.0;
        if(chr2 == 'W') jd1 *= -1.0;
        p1.x = cos(wd1) * cos(jd1);
        p1.y = cos(wd1) * sin(jd1);
        p1.z = sin(wd1);
        scanf("%lf %lf %c %lf %lf %c", &w2, &wm2, &chr1, &j2, &jm2, &chr2);
        wd2 = (w2 + wm2 / 60) * pi / 180;
        jd2 = (j2 + jm2 / 60) * pi / 180;
        if(chr1 == 'S') wd2 *= -1.0;
        if(chr2 == 'W') jd2 *= -1.0;
        p2.x = cos(wd2) * cos(jd2);
        p2.y = cos(wd2) * sin(jd2);
        p2.z = sin(wd2);
        double a = acos(p1.x * p2.x + p1.y * p2.y + p1.z * p2.z);
        printf("%.3lf\n", a * 6370.0);   
    }
    return 0;
}
*/
//longitude  经度 
//latitude   纬度 
#include <math.h>
#include <stdio.h>

#define pi acos(-1.0)
#define sqr(a) ((a) * (a))

struct point 
{
	double x, y, z;
	double  latitude, longitude;
	double l1, l2;
	void input()
	{
		scanf("%lf%lf", &latitude, &longitude);
		l1 = latitude;
		l2 = longitude;
		latitude *= pi / 180;
		longitude *= pi / 180;
		x = cos(latitude) * cos(longitude);
        y = cos(latitude) * sin(longitude);
        z = sin(latitude);
	}
	double dis(point &b)
	{
		return acos(x * b.x + y * b.y + z * b.z);
	}
};

int main()
{
	int n, u;
	point p[1005];
	while(scanf("%d", &n) != EOF)
	{
		for(int i = 0;i < n;i++)
			p[i].input();
		u = 0;
		double mindis = 1e250, maxdis, tmp;
		for(int i = 0;i < n;i++)
		{
			maxdis = -2;
			for(int j = 0;j < n;j++)
			{
				tmp = p[i].dis(p[j]);
				if(tmp > maxdis) maxdis = tmp;
			}
			if(maxdis < mindis) 
			{
				mindis = maxdis;
				u = i;
			}
		}
		printf("%.2lf %.2lf\n", p[u].l1, p[u].l2);	
	}
	return 0;
}

[计算几何]计算几何模板下载(一)

 

点击下载   计算几何_陈海丰.doc

(1)凸包
(2)判断两条线段是否相交(平行,不平行)
(3)三角形的外接圆(已知不在同一直线上的三点求经过三点的圆)
(4)三角形的垂心内心重心中垂线
(5)求直线的交点
(6)根据线段两端点的坐标求垂直平分线上除中点外的另一点
(7)根据两点坐标求直线方程
(8)差积的应用
(9)三角形的面积公式
(10)三角形的内接圆(未检验正确性)
(11)多边形的面积(适合凹多边形)
(12)判断点是否在线段上
(13)平面上两个点之间的距离
(14)p点关于直线L的对称点
(15)判断一个矩形是否在另一个矩形中
(16)直线和圆的交点+点关于线的对称点+点到线的距离+直线方程(fzu_1035)
(17)判断点是否在多边形内
(18)N点中三个点组成三角形面积最大
(19)扇形的重心
(20)多边形的重心
(21)判断N点是否共面
(22)求共线的点最多为多少
(23)N个矩形的相交的面积
(24)三角形外接圆+圆的参数方程(pku_1266)
(25)判断线段是否有交点并求交点(cug_1078)
(26)简单多边形的核
(27)线段重叠+投影(pku_1375)
(28)二分+圆的参数方程(pku_2600)
(29)Pick公式
(30)根据经度纬度求球面距离
(31)两圆切线的交点
(32)线段与三角形的交(usaco_3.4)

[C/C++函数]atan, atan2

atan, atan2

Calculates the arctangent of x (atan) or the arctangent of y/x (atan2).

double atan( double x );

double atan2( double y, double x );

Routine

Required Header

Compatibility

atan

<math.h>

ANSI, Win 95, Win NT

atan2

<math.h>

ANSI, Win 95, Win NT

 

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB

Single thread static library, retail version

LIBCMT.LIB

Multithread static library, retail version

MSVCRT.LIB

Import library for MSVCRT.DLL, retail version

 

Return Value

atan returns the arctangent of x. atan2 returns the arctangent of y/x. If x is 0, atan returns 0. If both parameters of atan2 are 0, the function returns 0. You can modify error handling by using the _matherr routine. atan returns a value in the range –π/2 to π/2 radians; atan2 returns a value in the range –π to π radians, using the signs of both parameters to determine the quadrant of the return value.

Parameters

x, y

Any numbers

Remarks

The atan function calculates the arctangent of x. atan2 calculates the arctangent of y/x. atan2 is well defined for every point other than the origin, even if x equals 0 and y does not equal 0.

Example

/* ATAN.C: This program calculates 
 * the arctangent of 1 and -1.
 */


void main( void ) 
{
   double x1, x2, y;

   printf( "Enter a real number: " );
   scanf( "%lf", &x1 );
   y = atan( x1 );
   printf( "Arctangent of %f: %f\n", x1, y );
   printf( "Enter a second real number: " );
   scanf( "%lf", &x2 );
   y = atan2( x1, x2 );
   printf( "Arctangent of %f / %f: %f\n", x1, x2, y );

Output

Enter a real number: -862.42
Arctangent of -862.420000: -1.569637
Enter a second real number: 78.5149
Arctangent of -862.420000 / 78.514900: -1.480006

Floating-Point Support Routines

See Also   acos, asin, cos, _matherr, sin, tan

 

[计算几何]几何公式

几何公式

【三角形】:

1. 半周长 P=(a+b+c)/2

2. 面积 S=aHa/2=absin(C)/2=sqrt(P(P-a)(P-b)(P-c))

3. 中线 Ma=sqrt(2(b^2+c^2)-a^2)/2=sqrt(b^2+c^2+2bccos(A))/2

4. 角平分线 Ta=sqrt(bc((b+c)^2-a^2))/(b+c)=2bccos(A/2)/(b+c)

5. 高线 Ha=bsin(C)=csin(B)=sqrt(b^2-((a^2+b^2-c^2)/(2a))^2)

6. 内切圆半径 r=S/P=asin(B/2)sin(C/2)/sin((B+C)/2)

               =4Rsin(A/2)sin(B/2)sin(C/2)=sqrt((P-a)(P-b)(P-c)/P)

               =Ptan(A/2)tan(B/2)tan(C/2)

7. 外接圆半径 R=abc/(4S)=a/(2sin(A))=b/(2sin(B))=c/(2sin(C))

【四边形】:

D1,D2为对角线,M对角线中点连线,A为对角线夹角

1. a^2+b^2+c^2+d^2=D1^2+D2^2+4M^2

2. S=D1D2sin(A)/2

(以下对圆的内接四边形)

3. ac+bd=D1D2

4. S=sqrt((P-a)(P-b)(P-c)(P-d)),P为半周长

【正n边形】:

R为外接圆半径,r为内切圆半径

1. 中心角 A=2PI/n

2. 内角 C=(n-2)PI/n

3. 边长 a=2sqrt(R^2-r^2)=2Rsin(A/2)=2rtan(A/2)

4. 面积 S=nar/2=nr^2tan(A/2)=nR^2sin(A)/2=na^2/(4tan(A/2))

【圆】:

1. 弧长 L=rA

2. 弦长 a=2sqrt(2hr-h^2)=2rsin(A/2)

3. 弓形高 h=r-sqrt(r^2-a^2/4)=r(1-cos(A/2))=atan(A/4)/2

4. 扇形面积 S1=rl/2=r^2A/2

5. 弓形面积 S2=(rl-a(r-h))/2=r^2(A-sin(A))/2

【棱柱】:

1. 体积 V=Ah,A为底面积,h为高

2. 侧面积 S=lp,l为棱长,p为直截面周长

3. 全面积 T=S+2A

【棱锥】:

1. 体积 V=Ah/3,A为底面积,h为高

(以下对正棱锥)

2. 侧面积 S=lp/2,l为斜高,p为底面周长

3. 全面积 T=S+A

【棱台】:

1. 体积 V=(A1+A2+sqrt(A1A2))h/3,A1.A2为上下底面积,h为高

(以下为正棱台)

2. 侧面积 S=(p1+p2)L/2,p1.p2为上下底面周长,l为斜高

3. 全面积 T=S+A1+A2

【圆柱】:

1. 侧面积 S=2PIrh

2. 全面积 T=2PIr(h+r)

3. 体积 V=PIr^2h

【圆锥】:

1. 母线 L=sqrt(h^2+r^2)

2. 侧面积 S=PIrl

3. 全面积 T=PIr(L+r)

4. 体积 V=PIr^2h/3

【圆台】:

1. 母线 L=sqrt(h^2+(r1-r2)^2)

2. 侧面积 S=PI(r1+r2)L

3. 全面积 T=PIr1(L+r1)+PIr2(L+r2)

4. 体积 V=PI(r1^2+r2^2+r1r2)h/3

【球】:

1. 全面积 T=4PIr^2

2. 体积 V=4PIr^3/3

【球台】:

1. 侧面积 S=2PIrh

2. 全面积 T=PI(2rh+r1^2+r2^2)

3. 体积 V=PIh(3(r1^2+r2^2)+h^2)/6

【球扇形】:

1. 全面积 T=PIr(2h+r0),h为球冠高,r0为球冠底面半径

2. 体积 V=2PIr^2h/3

clip_image002Euler的任意四面体体积公式(已知边长求体积)

clip_image004  

已知4点坐标求体积(其中四个点的坐标分别为(x1,y1,z1,x2,y2,z2,x3,y3,z3,x4,y4,z4clip_image006

 

 

 

注意事项:

1. 注意舍入方式(0.5的舍入方向);防止输出-0.

2. 几何题注意多测试不对称数据.

3. 整数几何注意xmultdmult是否会出界;

   符点几何注意eps的使用.

4. 避免使用斜率;注意除数是否会为0.

5. 公式一定要化简后再代入.

6. 判断同一个2*PI域内两角度差应该是

   abs(a1-a2)<beta||abs(a1-a2)>pi+pi-beta;

   相等应该是

   abs(a1-a2)<eps||abs(a1-a2)>pi+pi-eps;

7. 需要的话尽量使用atan2,注意:atan2(0,0)=0,

   atan2(1,0)=pi/2,atan2(-1,0)=-pi/2,atan2(0,1)=0,atan2(0,-1)=pi.

8. cross product = |u|*|v|*sin(a)

   dot product = |u|*|v|*cos(a)

9. (P1-P0)x(P2-P0)结果的意义:

   : <P0,P1><P0,P2>顺时针(0,pi)

   : <P0,P1><P0,P2>逆时针(0,pi)

   0 : <P0,P1>,<P0,P2>共线,夹角为0pi

 

 

[计算几何]长方体上一点到原点的距离(pku2977)

http://acm.pku.edu.cn/JudgeOnline/problem?id=2977

Box walking

Description

You are given a three-dimensional box of integral dimensions lx × ly × lz The edges of the box are axis-aligned, and one corner of the box is located at position (0, 0, 0). Given the coordinates (x, y, z) of some arbitrary position on the surface of the box, your goal is to return the square of the length of the shortest path along the box’s surface from (0, 0, 0) to (x, y, z).

If lx = 1, ly = 2, and lz = 1, then the shortest path from (0, 0, 0) to (1, 2, 1) is found by walking from (0, 0, 0) to (1, 1, 0), followed by walking from (1, 1, 0) to (1, 2, 1). The total path length is √8.

Input

The input test file will contain multiple test cases, each of which consists of six integers lx, ly, lz, x, y, z where 1 ≤ lx, ly, lz ≤ 1000. Note that the box may have zero volume, but the point (x, y, z) is always guaranteed to be on one of the six sides of the box. The end-of-file is marked by a test case with lx = ly = lz = x = y = z = 0 and should not be processed.

Output

For each test case, write a single line with a positive integer indicating the square of the shortest path length. (Note: The square of the path length is always an integer; thus, your answer is exact, not approximate.)

Sample Input

1 1 2 1 1 2
1 1 1 1 1 1
0 0 0 0 0 0

Sample Output

8
5

Source

Stanford Local 2005

/*
Box
---

Figuring out the shortest path on a box may seem trivial at first.
All we need to do is find the unfolding of the box that brings
the destination point closest.
If the final point is on one of the three faces touching the origin,
the shortest path is always a straight line directly to the destination;
if it's on one of the other three faces, it may seem obvious that we can
start on a face adjacent to the final face, and then just go around a
single corner.  It may seem obvious, that is, but it is wrong.

Consider a box that has a width of 100 units, and a height and depth
of 4 units, and let's say our destination is (100,3,3).  If we
use the face perpendicular to the depth and adjacent with the origin,
and then the destination face, we must traverse 103 units horizontally
and 3 units vertically for a total distance of 103 and some change:

   |--------~...~------------|----|
   |                         |   *|
   |                         |    |
   |                         |    |
   *--------~...~------------|----|

If on the other hand we use both the face perpendicular to the
depth and the one on top of that we can cut this down to 101
units horizontally and 7 units vertically for a total distance
of only 101 and some change:

   |--------~...~------------|----|
   |                         |*   |
   |                         |    |
   |                         |    |
   |--------~...~------------|----|
   |                         |
   |                         |
   |                         |
   *--------~...~------------|

So sometimes we will need to traverse three faces to get to
our final point the quickest way.  Do we ever need to traverse
four or more faces?  In this problem, probably not, but it
turns out we don't need to know that; we can easily enumerate
all single, two-face, three-face, four-face, and even more
using recursion.

Indeed, manually enumerating and coding all the cases is
terribly error-prone and very difficult to test; a single sign
error or coordinate swap can doom your submission.  So writing
the general case is much safer.

We'll start with a routine that enumerates the unfoldings
starting with a single face.  If the final destination is on
that face, the shortest path is always directly to that
point (every subpath of the final shortest path is itself a
straight line on the unfolded box).  Otherwise, we need to
traverse either over the right edge, or over the top edge,
to the next face.  As we cross each edge, we need to
accumulate how much horizontal and vertical distance we have
covered.

long best = Integer.MAX_VALUE ;
long sqadd(int x, int y) {
   return x * (long)x + y * (long)y ;
}
void rec(
   int x, int y,        // the distance we've traversed so far
   int w, int h, int d, // the width and height of the current face, and
                        // depth of the box in this orientation
   int dx, int dy, int dz, // the position of the destination
   int togo) {          // how many additional faces we allow ourselves
   if (dz == 0) { // the destination is on this face
      best = Math.min(best, sqadd(x+dx, y+dy)) ;
      return ;
   }
   if (togo == 0) return ; // no more faces allowed
   // now we consider going to the right edge; this rotates the box and point
   rec(x + w, y, d, h, w, dz, dy, w-dx, togo-1) ;
   // now we consider going to the top edge; this rotates the box and point
   rec(x, y + h, w, d, h, dx, dz, h-dy, togo-1) ;
}

Finally, in the main routine, we need to consider all three
possible starting faces.  We don't know how many faces a best path
might be, so we be generous and say 6.  This is only a maximum of
2^6 * 3 cases, so it runs very fast.

for (each case) {
   best = Integer.MAX_VALUE ;
   rec(0, 0, w, h, d, x, y, z, 6) ;
   rec(0, 0, h, d, w, y, z, x, 6) ;
   rec(0, 0, d, w, h, z, x, y, 6) ;
}

There's one other concern we may have.  We are considering all
unfoldings, even the unfoldings for which the straight line from
the origin to the (unfolded) destination goes off the actual
unfolded box.  In such a case, the path will always be longer
than the final best result, so considering it doesn't hurt
anything.  Essentially, all the space outside the unfolding
represents the edges of the box "opened up" or "stretched";
by opening those edges that way, you can only increase the
overall path length.  Consider the picture below:

         |----|
         |*   |
         /    |
        /|    |
   |---/-|----|
   |  /  |    |
   | /   |    |
   |/    |    |
   *-----|----|

Our straight line leaves the leftmost rectangle and reenters
the topmost rectangle.  But the two edges so represented
are actually joined in the real box, so a different unfolding
for which that line does not leave the unfolding always will
have a shorter distance:

   |-----|
   |     |
   |     |
   |*    |
   |-----|
   |     |
   |     |
   |     |
   *-----|

But if you were worried about this not being the case, it is
straightforward to extend the recursion to maintain a minimum
and maximum slope (represented by rationals) permitted by this
straight-line traversals, and thus eliminate all unfoldings for
which a straight line would leave the boundaries.
*/
#include <stdio.h>

#define sqr(x) ((x) * (x))
#define min(a, b) ((a) < (b) ? (a) : (b))

int length(int lx, int ly, int lz, int x, int y, int z)
{
	int d = sqr(lx + y) + sqr(z);
	d = min(d, sqr(lx + z) + sqr(y));
	d = min(d, sqr(lx + lz - z) + sqr(y + lz));
	return min(d, sqr(lx + ly - y) + sqr(z + ly));
}

int slove(int lx, int ly, int lz, int x, int y, int z)
{
	if(x == 0 || y == 0 || z == 0) return sqr(x) + sqr(y) + sqr(z);
	else if(x == lx) return length(lx, ly, lz, x, y, z);
	else if(y == ly) return length(ly, lx, lz, y, x, z);
	else if(z == lz) return length(lz, lx, ly, z, x, y);
}

int main()
{
	freopen("box.in", "r", stdin);
	freopen("out.txt", "w", stdout);
	int lx, ly, lz, x, y, z;
	while(scanf("%d%d%d%d%d%d", &lx, &ly, &lz, &x, &y, &z) != EOF)
	{
		if(!lx && !ly && !lz && !x && !y && !z) break;
		printf("%d\n", slove(lx, ly, lz, x, y, z));
	}
	return 0;
}
 

经典书籍收藏

 
There are no photo albums.
感谢访问!
Please wait...
Sorry, the comment you entered is too long. Please shorten it.
You didn't enter anything. Please try again.
Sorry, we can't add your comment right now. Please try again later.
To add a comment, you need permission from your parent. Ask for permission
Your parent has turned off comments.
Sorry, we can't delete your comment right now. Please try again later.
You've exceeded the maximum number of comments that can be left in one day. Please try again in 24 hours.
Your account has had the ability to leave comments disabled because our systems indicate that you may be spamming other users. If you believe that your account has been disabled in error please contact Windows Live support.
Complete the security check below to finish leaving your comment.
The characters you type in the security check must match the characters in the picture or audio.
HaiFeng Chenwrote:
这个是差分约束来吧
Nov. 21
之昊 王wrote:
请问pku1201 用DP怎么做的?
Nov. 20