├── Dancing Links ├── Dancing Links Sudoku 模板.cpp └── Dancing Links 模板.cpp ├── HASH ├── 字符串哈希 模板.c ├── 字符串哈希 模板.cpp ├── 散列HASH 模板.cpp └── 整数哈希 模板.cpp ├── README.md ├── RMQ ├── RMQ_1D 模板.cpp ├── RMQ_2D 模板.cpp └── RMQ_GCD 模板.cpp ├── 《夜深人静写算法》.png ├── 动态规划 ├── dp单调队列 最大K子串 模板.cpp ├── dp斜率优化 模板.cpp ├── dp斜率优化(2D) 模板.cpp ├── 单调队列 模板.cpp ├── 数位 DP 模板.cpp ├── 最大完全子矩阵 模板.cpp ├── 最小编辑距离 │ ├── Levenshtein 路径回溯.cpp │ └── Levenshtein.cpp ├── 最长公共子序列 │ ├── 最长公共子序列 优化版.cpp │ ├── 最长公共子序列 模板.cpp │ ├── 最长公共子序列 路径回溯 模板.cpp │ ├── 最长公共子序列(滚动数组) 模板.cpp │ └── 最长公共递增子序列 模板.cpp ├── 最长单调子序列.cpp └── 背包问题 │ ├── 01背包 K优解 模板.cpp │ ├── 01背包 模板(滚动数组).cpp │ ├── 01背包 模板.cpp │ ├── 主件附件依赖背包 模板.cpp │ ├── 二维 01背包 模板.cpp │ ├── 分组背包 (最多一个) 模板.cpp │ ├── 分组背包 (至少一个) 模板.cpp │ ├── 多重背包 模板.cpp │ ├── 完全背包 模板.cpp │ └── 树上分组背包 模板.cpp ├── 图论 ├── 二分图 │ ├── 二分图最大匹配 邻接表.cpp │ └── 二分图最大匹配 链式前向星.cpp ├── 差分约束模板.cpp ├── 并查集 │ ├── 并查集 判奇环.cpp │ ├── 并查集 求解方程组合法性.cpp │ └── 并查集 路径压缩.cpp ├── 广度优先搜索 │ ├── PushBoxGame │ │ ├── PushBoxGame.sln │ │ ├── PushBoxGame.v12.suo │ │ └── PushBoxGame │ │ │ ├── Mission │ │ │ ├── 1.x │ │ │ ├── 10.x │ │ │ ├── 11.x │ │ │ ├── 2.x │ │ │ ├── 3.x │ │ │ ├── 4.x │ │ │ ├── 5.x │ │ │ ├── 6.x │ │ │ ├── 7.x │ │ │ ├── 8.x │ │ │ └── 9.x │ │ │ ├── PushBoxGame.vcxproj │ │ │ ├── PushBoxGame.vcxproj.filters │ │ │ ├── commondef.h │ │ │ ├── hash.cpp │ │ │ ├── hash.h │ │ │ ├── main.cpp │ │ │ ├── path.cpp │ │ │ ├── path.h │ │ │ ├── pushboxgame.cpp │ │ │ ├── pushboxgame.h │ │ │ ├── pushboxstate.cpp │ │ │ └── pushboxstate.h │ ├── 最短路BFS样例.cpp │ ├── 迷宫搜索 模板.cpp │ └── 迷宫救公主.cpp ├── 强连通分量 │ └── 2_sat 模板.cpp ├── 最短路 │ ├── BellmanFord 模板.cpp │ ├── Dijkstra + Heap 模板.cpp │ ├── Dijkstra 模板.cpp │ ├── FloydWarshall 模板.cpp │ └── SPFA 模板.cpp ├── 最近公共祖先 模板.cpp ├── 深度优先搜索 │ ├── 全排列DFS样例.cpp │ ├── 斐波那契数列DFS样例.cpp │ ├── 简易DFS样例.cpp │ ├── 记忆化搜索求最大值样例.cpp │ └── 阶乘求解DFS样例.cpp └── 稳定婚姻 模板.cpp ├── 大数 ├── KaraTsuba 模板.cpp ├── 大数 模板.cpp └── 高精分数 模板.cpp ├── 字符串 ├── Manacher 模板.cpp ├── kmp.c ├── 字典树 │ ├── 字典树 01模板.cpp │ ├── 字典树 力扣简易版.cpp │ └── 字典树 字母模板.cpp └── 朴素回文串.c ├── 数据结构 ├── 画解数据结构 │ ├── 二叉树 │ │ ├── 二叉搜索树 BST │ │ │ └── 二叉搜索树.c │ │ └── 平衡二叉树 AVL │ │ │ └── AVL 树.c │ ├── 双端队列 │ │ ├── 双端队列链表实现.c │ │ └── 双端队列顺序表实现.c │ ├── 哈希表 │ │ ├── 散列哈希 - 开方定址法.c │ │ └── 散列哈希 - 直接定址法.c │ ├── 图 │ │ └── 最小生成树 │ │ │ ├── boruvka.cpp │ │ │ ├── kruscal.cpp │ │ │ └── prim.cpp │ ├── 堆 │ │ └── 堆.c │ ├── 思维导图地址.txt │ ├── 排序 │ │ ├── 冒泡排序.cpp │ │ ├── 基数排序.cpp │ │ ├── 希尔排序.cpp │ │ ├── 归并排序.cpp │ │ ├── 快速排序 - 实现1.cpp │ │ ├── 快速排序 - 实现2.cpp │ │ ├── 插入排序.cpp │ │ ├── 计数排序.cpp │ │ └── 选择排序.cpp │ ├── 栈 │ │ ├── 线性表实现栈.c │ │ └── 链表实现栈.c │ ├── 树 │ │ ├── 二叉树链表存储.c │ │ ├── 孩子表示法.c │ │ ├── 左儿子右兄弟表示法.c │ │ ├── 父亲表示法.c │ │ └── 遍历.c │ ├── 链表 │ │ └── 单向链表.cpp │ ├── 队列 │ │ ├── 链表实现队列.c │ │ └── 顺序表实现队列.c │ └── 顺序表(数组) │ │ └── 数组的基本操作.c └── 高级数据结构 │ ├── 单调栈 │ ├── 单调栈 模板.cpp │ └── 直方图的最大子矩形.cpp │ └── 单调队列 │ └── 单调队列.c ├── 数论 ├── Eratosthenes筛选 模板.cpp ├── Lucas定理 模板.cpp ├── 中国剩余定理 │ ├── 中国剩余定理 模板.cpp │ └── 朴素枚举 模板.cpp ├── 二分快速幂.cpp ├── 因子加减法 模板.cpp ├── 因子筛选.cpp ├── 因式分解.cpp ├── 扩展欧拉定理 模板.cpp ├── 拉宾米勒大数判素 模板.cpp ├── 整数分块.cpp ├── 模幂循环节.cpp ├── 欧拉函数 模板.cpp ├── 欧拉函数 筛选法 模板.cpp ├── 线性同余 模板.cpp ├── 逆元 │ ├── 扩展欧几里得 逆元 模板.cpp │ └── 递推 逆元 模板.cpp └── 递归枚举因子 模板.cpp ├── 杂项 ├── 游标时间复杂度均摊.cpp ├── 蜂巢坐标系 模板.cpp └── 输入加速.cpp ├── 枚举 ├── 二分枚举 │ ├── 二分枚举 函数 模板.c │ └── 二分枚举 数组 模板.c └── 暴力枚举 │ └── 线性枚举.c ├── 树 ├── 树的直径 模板.cpp ├── 矩形树_最值 模板.cpp └── 线段树_最值 模板.cpp ├── 树状数组 ├── 一维树状数组 模板.cpp ├── 三维树状数组 模板.cpp └── 二维树状数组 模板.cpp ├── 矩阵 ├── 矩阵 ijk 模板.cpp ├── 矩阵 ikj 模板.cpp ├── 矩阵乘法 模板.cpp └── 矩阵乘法.bmp ├── 组合数学 ├── Polya环形计数 模板.cpp ├── 多重集排列 模板.cpp └── 置换群 模板.cpp ├── 计算几何 ├── 半平面交 模板.cpp ├── 模拟退火 模板.cpp ├── 解析几何_线段交点.cpp ├── 计算几何 3D点的旋转.cpp ├── 计算几何 二维凸包.cpp ├── 计算几何 圆和多边形的交 模板.cpp ├── 计算几何 圆相关 模板.cpp ├── 计算几何 最大空凸包.cpp ├── 计算几何 最小包围球 模板.cpp ├── 计算几何 最小覆盖圆 模板.cpp ├── 计算几何2D模板.cpp └── 计算几何_线段判交 模板.cpp └── 高等数学 ├── Simpson.cpp ├── 最小分数表示趋近.cpp └── 高斯消元 模板.cpp /Dancing Links/Dancing Links Sudoku 模板.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 数独的DancingLinks构造 3 | 4 | 1) 每个格子只能填1个数; 5 | 2) 每行的数字集合为[1, N^2],且不能重复; 6 | 3) 每列的数字集合为[1, N^2],且不能重复; 7 | 4) 每个“宫”的数字集合为[1, N^2],且不能重复(其中“宫”的意思就是N×N的格子。对于N=3的情况,就是“九宫格”); 8 | 9 | 转变为精确覆盖问题。行代表问题的所有情况,列代表问题的约束条件。 10 | 每个格子能够填的数字为[1,9],并且总共有9×9(即3^2×3^2)个格子,所以总的情况数为729种。也就是DancingLinks的行为729行。 11 | 12 | 列则分为四种: 13 | 1) [0, 81)列 分别对应了81个格子是否被放置了数字。 14 | 2) [82, 2*81)列 分别对应了9行,每行[1, 9]个数字的放置情况; 15 | 3) [2*81, 3*81)列 分别对应了9列,每列[1, 9]个数字的放置情况; 16 | 4) [3*81, 4*81)列 分别对应了9个“宫”,每“宫”[1, 9]个数字的放置情况; 17 | 18 | Author: WhereIsHeroFrom 19 | Update Time: 2018-3-21 20 | Algorithm Complexity: 非多项式算法 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | using namespace std; 27 | 28 | #define SDK_CNT 4 29 | #define SDK_MAX (SDK_CNT*SDK_CNT) 30 | #define SDK_BLOCK (SDK_MAX*SDK_MAX) 31 | 32 | #define MAXR (SDK_BLOCK*SDK_MAX+10) 33 | #define MAXC (SDK_BLOCK*4+10) 34 | #define INF -1 35 | #define INT64 __int64 36 | 37 | enum eCoverType { 38 | ECT_EXACT = 0, // 精确覆盖 39 | ECT_REPEAT = 1, // 重复覆盖 40 | }; 41 | 42 | enum eDanceType { 43 | EDT_GET_ONE_SOLUTION = 0, // 获取一个解 44 | EDT_JUDGE_MULTIPLE = 1, // 判断是否多个解 45 | }; 46 | 47 | /* 48 | DLXNode 49 | left, right 十字交叉双向循环链表的左右指针 50 | up, down 十字交叉双向循环链表的上下指针 51 | 52 | <用于列首结点> 53 | colSum 列的结点总数 54 | colIdx 列的编号 55 | 56 | <用于行首结点/元素结点> 57 | colHead 指向列首结点的指针 58 | rowIdx DLXNode结点在原矩阵中的行标号 59 | */ 60 | class DLXNode { 61 | public: 62 | DLXNode *left, *right, *up, *down; 63 | union { 64 | struct { 65 | DLXNode *colHead; 66 | int rowIdx; 67 | }node; 68 | struct { 69 | int colIdx; 70 | int colSum; 71 | }col; 72 | }data; 73 | public: 74 | ////////////////////////////////////////////////////////// 75 | // 获取/设置 接口 76 | void resetCol(int colIdx); 77 | void resetColSum(); 78 | void updateColSum(int delta); 79 | int getColSum(); 80 | 81 | void setColIdx(int colIdx); 82 | int getColIdx(); 83 | 84 | void setColHead(DLXNode *colPtr); 85 | DLXNode *getColHead(); 86 | 87 | void setRowIdx(int rowIdx); 88 | int getRowIdx(); 89 | 90 | /////////////////////////////////////////////////////////// 91 | // 搜索求解用到的接口 92 | void appendToCol(DLXNode *colPtr); 93 | void appendToRow(DLXNode *rowPtr); 94 | 95 | void deleteFromCol(); 96 | void resumeFromCol(); 97 | 98 | void deleteFromRow(); 99 | void resumeFromRow(); 100 | /////////////////////////////////////////////////////////// 101 | }; 102 | 103 | void DLXNode::resetCol(int colIdx) { 104 | // IDA*的时候需要用到列下标进行hash 105 | setColIdx(colIdx); 106 | // 初始化每列结点个数皆为0 107 | resetColSum(); 108 | } 109 | void DLXNode::resetColSum() { 110 | data.col.colSum = 0; 111 | } 112 | 113 | void DLXNode::updateColSum(int delta) { 114 | data.col.colSum += delta; 115 | } 116 | 117 | int DLXNode::getColSum() { 118 | return data.col.colSum; 119 | } 120 | 121 | void DLXNode::setColIdx(int colIdx) { 122 | data.col.colIdx = colIdx; 123 | } 124 | int DLXNode::getColIdx() { 125 | return data.col.colIdx; 126 | } 127 | 128 | void DLXNode::setColHead(DLXNode * colPtr) { 129 | data.node.colHead = colPtr; 130 | } 131 | 132 | DLXNode* DLXNode::getColHead() { 133 | return data.node.colHead; 134 | } 135 | 136 | void DLXNode::setRowIdx(int rowIdx) { 137 | data.node.rowIdx = rowIdx; 138 | } 139 | 140 | int DLXNode::getRowIdx() { 141 | return data.node.rowIdx; 142 | } 143 | 144 | void DLXNode::appendToCol(DLXNode * colPtr) { 145 | // 赋值列首指针 146 | setColHead(colPtr); 147 | 148 | // 这几句要求插入结点顺序保证列递增,否则会导致乱序(每次插在一列的最后) 149 | up = colPtr->up; 150 | down = colPtr; 151 | colPtr->up = colPtr->up->down = this; 152 | 153 | // 列元素++ 154 | colPtr->updateColSum(1); 155 | } 156 | 157 | void DLXNode::appendToRow(DLXNode* rowPtr) { 158 | // 赋值行编号 159 | setRowIdx(rowPtr->getRowIdx()); 160 | 161 | // 这几句要求插入结点顺序保证行递增(每次插在一行的最后) 162 | left = rowPtr->left; 163 | right = rowPtr; 164 | rowPtr->left = rowPtr->left->right = this; 165 | } 166 | 167 | void DLXNode::deleteFromCol() { 168 | left->right = right; 169 | right->left = left; 170 | } 171 | 172 | void DLXNode::resumeFromCol() { 173 | right->left = left->right = this; 174 | } 175 | 176 | void DLXNode::deleteFromRow() { 177 | up->down = down; 178 | down->up = up; 179 | if (getColHead()) 180 | getColHead()->updateColSum(-1); 181 | } 182 | 183 | void DLXNode::resumeFromRow() { 184 | if (getColHead()) 185 | getColHead()->updateColSum(1); 186 | up->down = down->up = this; 187 | } 188 | 189 | /* 190 | DLX (单例) 191 | head head 只有左右(left、right)两个指针有效,指向列首 192 | rowCount, colCount 本次样例矩阵的规模(行列数) 193 | row[] 行首结点列表 194 | col[] 列首结点列表 195 | 196 | dlx_pool 结点对象池(配合dlx_pool_idx取对象) 197 | */ 198 | class DLX { 199 | DLXNode *head; // 总表头 200 | int rowCount, colCount; // 本次样例矩阵的规模(行列数) 201 | DLXNode *row, *col; // 行首结点列表 / 列首结点列表 202 | 203 | DLXNode *dlx_pool; // 结点对象池 204 | int dlx_pool_idx; // 结点对象池下标 205 | 206 | eCoverType eCType; 207 | eDanceType eDType; 208 | int *col_coverd; // 标记第i列是否覆盖,避免重复覆盖 209 | INT64 *row_code; // 每行采用二进制标记进行优化 210 | int limitColCount; // 限制列的个数 211 | // 即 前 limitColCount 列满足每列1个"1",就算搜索结束 212 | // 一般情况下 limitColCount == colCount 213 | public: 214 | int *result, resultCount; // 结果数组 215 | int solutionCount; // 解数量 216 | 217 | private: 218 | DLX() { 219 | dlx_pool_idx = 0; 220 | head = NULL; 221 | dlx_pool = new DLXNode[MAXR*MAXC]; 222 | col = new DLXNode[MAXC+1]; 223 | row = new DLXNode[MAXR]; 224 | result = new int[MAXR]; 225 | col_coverd = new int[MAXC+1]; 226 | row_code = new INT64[MAXR]; 227 | } 228 | 229 | ~DLX() { 230 | delete [] dlx_pool; 231 | delete [] col; 232 | delete [] row; 233 | delete [] result; 234 | delete [] col_coverd; 235 | delete [] row_code; 236 | } 237 | 238 | void reset_size(int r, int c, int limitC = INF, eCoverType ect = ECT_EXACT, eDanceType edt = EDT_GET_ONE_SOLUTION) { 239 | rowCount = r; 240 | colCount = c; 241 | limitColCount = limitC != INF? limitC : c; 242 | eCType = ect; 243 | eDType = edt; 244 | dlx_pool_idx = 0; 245 | resultCount = -1; 246 | solutionCount = 0; 247 | } 248 | 249 | void reset_col(); 250 | void reset_row(); 251 | DLXNode* get_node(); 252 | DLXNode* get_min_col(); 253 | int get_eval(); // 估价函数 254 | 255 | void cover(DLXNode *colPtr); 256 | void uncover(DLXNode *colPtr); 257 | 258 | void coverRow(DLXNode *nodePtr); 259 | void uncoverRow(DLXNode *nodePtr); 260 | 261 | bool isEmpty(); 262 | public: 263 | 264 | void init(int r, int c, int limitC, eCoverType ect, eDanceType edt); 265 | void add(int rowIdx, int colIdx); // index 0-based 266 | void output(); 267 | bool dance(int depth, int maxDepth); 268 | void preCoverRow(int rowIndex); 269 | 270 | static DLX& Instance() { 271 | static DLX inst; 272 | return inst; 273 | } 274 | }; 275 | 276 | void DLX::reset_col() { 277 | // [0, colCount)作为列首元素, 278 | // 第colCount个列首元素的地址作为总表头head 279 | for(int i = 0; i <= colCount; ++i) { 280 | DLXNode *colPtr = &col[i]; 281 | colPtr->resetCol(i); 282 | // 初始化,每列元素为空,所以列首指针上下循环指向自己 283 | colPtr->up = colPtr->down = colPtr; 284 | // 第i个元素指向第i-1个,当i==0,则指向第colCount个,构成循环 285 | colPtr->left = &col[(i+colCount)%(colCount+1)]; 286 | // 第i个元素指向第i+1个,当i==colCount,则指向第0个,构成循环 287 | colPtr->right = &col[(i+1)%(colCount+1)]; 288 | col_coverd[i] = 0; 289 | } 290 | // 取第colCount个列首元素的地址作为总表头 291 | head = &col[colCount]; 292 | } 293 | 294 | void DLX::reset_row() { 295 | for(int i = 0; i < rowCount; ++i) { 296 | // 初始化行首结点 297 | DLXNode *rowPtr = &row[i]; 298 | // 初始化行,每行都为空,所以结点的各个指针都指向自己 299 | rowPtr->left = rowPtr->right = rowPtr->up = rowPtr->down = rowPtr; 300 | // 对应cover时候的函数入口的非空判断 301 | rowPtr->setColHead(NULL); 302 | rowPtr->setRowIdx(i); 303 | row_code[i] = 0; 304 | } 305 | } 306 | 307 | DLXNode* DLX::get_node() { 308 | return &dlx_pool[dlx_pool_idx++]; 309 | } 310 | 311 | void DLX::init(int r, int c, int limitC, eCoverType ect, eDanceType edt) { 312 | reset_size(r, c, limitC, ect, edt); 313 | reset_row(); 314 | reset_col(); 315 | } 316 | 317 | DLXNode* DLX::get_min_col() { 318 | DLXNode *resPtr = head->right; 319 | for(DLXNode *ptr = resPtr->right; ptr != head; ptr = ptr->right) { 320 | if(ptr->getColIdx() >= limitColCount) 321 | break; 322 | if(ptr->getColSum() < resPtr->getColSum()) { 323 | resPtr = ptr; 324 | } 325 | } 326 | return resPtr; 327 | } 328 | 329 | /* 330 | 功能:估价函数 331 | 注意:估计剩余列覆盖完还需要的行的个数的最小值 <= 实际需要的最小值 332 | */ 333 | int DLX::get_eval() { 334 | int eval = 0; 335 | INT64 row_status = 0; 336 | DLXNode *colPtr; 337 | 338 | // 枚举每一列 339 | for(colPtr = head->right; colPtr != head; colPtr = colPtr->right) { 340 | int colIdx = colPtr->getColIdx(); 341 | if(!(row_status & ((INT64)1)<down; nodePtr != colPtr; nodePtr = nodePtr->down) { 346 | row_status |= row_code[nodePtr->getRowIdx()]; 347 | } 348 | } 349 | } 350 | return eval; 351 | } 352 | 353 | /* 354 | 功能:插入一个(rowIdx, colIdx)的结点(即原01矩阵中(rowIdx, colIdx)位置为1的) 355 | 注意:按照行递增、列递增的顺序进行插入 356 | */ 357 | void DLX::add(int rowIdx, int colIdx) { 358 | DLXNode *nodePtr = get_node(); 359 | // 将结点插入到对应列尾 360 | nodePtr->appendToCol(&col[colIdx]); 361 | // 将结点插入到对应行尾 362 | nodePtr->appendToRow(&row[rowIdx]); 363 | row_code[rowIdx] |= ((INT64)1<right; nodePtr != rowPtr; nodePtr = nodePtr->right) { 375 | printf(" [%d]", nodePtr->getColHead()->getColIdx()); 376 | } 377 | puts(""); 378 | } 379 | } 380 | 381 | /* 382 | 功能:删除行 383 | 精确覆盖在删除列的时候,需要对行进行删除处理 384 | 枚举每个和nodePtr在同一行的结点p,执行删除操作 385 | */ 386 | void DLX::coverRow(DLXNode* nodePtr) { 387 | for(DLXNode *p = nodePtr->right; p != nodePtr; p = p->right) { 388 | p->deleteFromRow(); 389 | } 390 | } 391 | 392 | /* 393 | 功能:恢复行 394 | coverRow的逆操作 395 | */ 396 | void DLX::uncoverRow(DLXNode* nodePtr) { 397 | for(DLXNode *p = nodePtr->left; p != nodePtr; p = p->left) { 398 | p->resumeFromRow(); 399 | } 400 | } 401 | 402 | /* 403 | 功能:覆盖colPtr指向的那一列 404 | 说是覆盖,其实是删除那一列。 405 | 如果是精确覆盖,需要删除那列上所有结点对应的行,原因是,cover代表我会选择这列,这列上有1的行必须都删除 406 | */ 407 | void DLX::cover(DLXNode *colPtr) { 408 | if(!colPtr) { 409 | return; 410 | } 411 | if(!col_coverd[colPtr->getColIdx()]) { 412 | // 删除colPtr指向的那一列 413 | colPtr->deleteFromCol(); 414 | // 枚举每个在colPtr对应列上的结点p 415 | if (eCType == ECT_EXACT) { 416 | for(DLXNode* nodePtr = colPtr->down; nodePtr != colPtr; nodePtr = nodePtr->down) { 417 | coverRow(nodePtr); 418 | } 419 | } 420 | } 421 | ++col_coverd[colPtr->getColIdx()]; 422 | } 423 | 424 | /* 425 | 功能:恢复colPtr指向的那一列 426 | cover的逆操作 427 | */ 428 | void DLX::uncover(DLXNode* colPtr) { 429 | if(!colPtr) { 430 | return; 431 | } 432 | --col_coverd[colPtr->getColIdx()]; 433 | if(!col_coverd[colPtr->getColIdx()]) { 434 | // 枚举每个在colPtr对应列上的结点p 435 | if (eCType == ECT_EXACT) { 436 | for(DLXNode* nodePtr = colPtr->up; nodePtr != colPtr; nodePtr = nodePtr->up) { 437 | uncoverRow(nodePtr); 438 | } 439 | } 440 | // 恢复colPtr指向的那一列 441 | colPtr->resumeFromCol(); 442 | } 443 | } 444 | 445 | /* 446 | 功能:用于预先选择某行 447 | */ 448 | void DLX::preCoverRow(int rowIndex) { 449 | DLXNode *rowPtr = &row[rowIndex]; 450 | for(DLXNode *p = rowPtr->right; p != rowPtr; p = p->right) { 451 | cover(p->getColHead()); 452 | } 453 | } 454 | 455 | bool DLX::isEmpty() { 456 | if(head->right == head) { 457 | return true; 458 | } 459 | return head->right->getColIdx() >= limitColCount; 460 | } 461 | 462 | bool DLX::dance(int depth, int maxDepth=INF) { 463 | // 当前矩阵为空,说明找到一个可行解,算法终止 464 | if(isEmpty()) { 465 | resultCount = depth; 466 | if(eDType == EDT_GET_ONE_SOLUTION) { 467 | return true; 468 | } 469 | solutionCount ++; 470 | return solutionCount > 1; 471 | } 472 | if (maxDepth != INF) { 473 | if(depth + get_eval() > maxDepth) { 474 | return false; 475 | } 476 | } 477 | 478 | DLXNode *minPtr = get_min_col(); 479 | // 删除minPtr指向的列 480 | cover(minPtr); 481 | // minPtr为结点数最少的列,枚举这列上所有的行 482 | for(DLXNode *p = minPtr->down; p != minPtr; p = p->down) { 483 | // 令r = p->getRowIdx(),行r放入当前解 484 | result[depth] = p->getRowIdx(); 485 | // 行r上的结点对应的列进行删除 486 | for(DLXNode *q = p->right; q != p; q = q->right) { 487 | cover(q->getColHead()); 488 | } 489 | // 进入搜索树的下一层 490 | if(dance(depth+1, maxDepth)) { 491 | return true; 492 | } 493 | // 行r上的结点对应的列进行恢复 494 | for(DLXNode *q = p->left; q != p; q = q->left) { 495 | uncover(q->getColHead()); 496 | } 497 | } 498 | // 恢复minPtr指向的列 499 | uncover(minPtr); 500 | return false; 501 | } 502 | 503 | class Sudoku { 504 | int sdkMatrix[SDK_MAX][SDK_MAX]; //Sudoku矩阵, 数字范围为[1,SDK_MAX], 没有填的数字记为0 505 | int sdkCnt, sdkMax, sdkBlock; // sdkMax = sdkCnt^2, sdkBlock = sdkMax^2 506 | 507 | struct DLXRow { 508 | int sudokuNum; 509 | int sudokuRow, sudokuCol; 510 | 511 | DLXRow() {} 512 | DLXRow(int r, int c, int num): sudokuRow(r), sudokuCol(c), sudokuNum(num) {} 513 | }*dlxRow; 514 | int dlxRowCount; 515 | 516 | int getRegionIndex(int r, int c); 517 | void assignSize(int n); 518 | void fillSDKMatrix(char sdkTemp[SDK_MAX][SDK_MAX+1]); 519 | void createDancingLincks(eDanceType edt); 520 | void startDance(); 521 | 522 | public: 523 | Sudoku() { 524 | dlxRow = new DLXRow[MAXR]; 525 | } 526 | ~Sudoku() { 527 | delete [] dlxRow; 528 | } 529 | void outputSDKMatrix(); 530 | void startSolveSudoku(int n, eDanceType edt, char sdkTemp[SDK_MAX][SDK_MAX+1]); 531 | 532 | static Sudoku& Instance() { 533 | static Sudoku inst; 534 | return inst; 535 | } 536 | }; 537 | 538 | /* 539 | (0, sdkMax-1)-(0, sdkMax-1) => (0, sdkMax-1) 的映射 540 | 笛卡尔坐标(r, c) 到 "宫" 的映射 541 | */ 542 | int Sudoku::getRegionIndex(int r, int c) { 543 | return (r/sdkCnt)*sdkCnt + c/sdkCnt; 544 | } 545 | 546 | void Sudoku::assignSize(int n) { 547 | sdkCnt = n; 548 | sdkMax = sdkCnt * sdkCnt; 549 | sdkBlock = sdkMax * sdkMax; 550 | } 551 | 552 | void Sudoku::fillSDKMatrix(char sdkTemp[SDK_MAX][SDK_MAX+1]) { 553 | int i, j; 554 | for(i = 0; i < sdkMax; ++i) { 555 | for(j = 0; j < sdkMax; ++j) { 556 | int num = 0; 557 | if('A' <= sdkTemp[i][j] && sdkTemp[i][j] <= 'G') { 558 | num = (sdkTemp[i][j] - 'A' + 10); 559 | }else if('1' <= sdkTemp[i][j] && sdkTemp[i][j] <= '9') { 560 | num = (sdkTemp[i][j] - '0'); 561 | } 562 | sdkMatrix[i][j] = num; 563 | } 564 | } 565 | } 566 | 567 | void Sudoku::createDancingLincks(eDanceType edt) { 568 | DLX &dlx = DLX::Instance(); 569 | dlx.init(MAXR-1, sdkBlock*4, INF, ECT_EXACT, edt); 570 | dlxRowCount = 0; 571 | int i, j, k; 572 | for(i = 0; i < sdkMax; ++i) { 573 | for(j = 0; j < sdkMax; ++j) { 574 | for(k = 1; k <= sdkMax; ++k) { 575 | if(sdkMatrix[i][j] && sdkMatrix[i][j] != k) { 576 | continue; 577 | } 578 | // 格子限制:每格一个数 579 | dlx.add(dlxRowCount, i*sdkMax+j); 580 | // 行限制:每行只能一个k 581 | dlx.add(dlxRowCount, sdkBlock + i*sdkMax + (k-1)); 582 | // 列限制:每列只能一个k 583 | dlx.add(dlxRowCount, 2*sdkBlock + j*sdkMax + (k-1)); 584 | // 宫限制:每宫只能一个k 585 | dlx.add(dlxRowCount, 3*sdkBlock + getRegionIndex(i,j)*sdkMax + (k-1)); 586 | dlxRow[dlxRowCount++] = DLXRow(i, j, k); 587 | } 588 | } 589 | } 590 | // 总共 dlxRowCount 行 591 | } 592 | 593 | void Sudoku::startDance() { 594 | DLX &dlx = DLX::Instance(); 595 | dlx.dance(0, INF); 596 | int i; 597 | for(i = 0; i < dlx.resultCount; i++) { 598 | int &idx = dlx.result[i]; 599 | sdkMatrix[ dlxRow[idx].sudokuRow ][ dlxRow[idx].sudokuCol ] = dlxRow[idx].sudokuNum; 600 | } 601 | } 602 | 603 | void Sudoku::outputSDKMatrix() { 604 | int i, j; 605 | for(i = 0; i < sdkMax; ++i) { 606 | for(j = 0; j < sdkMax; ++j) { 607 | char c; 608 | if(1 <= sdkMatrix[i][j] && sdkMatrix[i][j] <= 9) { 609 | c = sdkMatrix[i][j] + '0'; 610 | }else { 611 | c = sdkMatrix[i][j] - 10 + 'A'; 612 | } 613 | printf("%c", c); 614 | } 615 | puts(""); 616 | } 617 | } 618 | 619 | void Sudoku::startSolveSudoku(int n, eDanceType edt, char sdkTemp[SDK_MAX][SDK_MAX+1]) { 620 | assignSize(n); 621 | fillSDKMatrix(sdkTemp); 622 | createDancingLincks(edt); 623 | startDance(); 624 | } 625 | 626 | char sdkTemp[SDK_MAX][SDK_MAX+1]; 627 | 628 | int main() { 629 | int i, j; 630 | int n; 631 | while(scanf("%d", &n) != EOF) { 632 | for(i = 0; i < n*n; ++i) { 633 | scanf("%s", sdkTemp[i]); 634 | } 635 | Sudoku &sdk = Sudoku::Instance(); 636 | sdk.startSolveSudoku(n, EDT_JUDGE_MULTIPLE, sdkTemp); 637 | DLX &dlx = DLX::Instance(); 638 | if (dlx.solutionCount == 0) { 639 | // 数独无解的情况 640 | printf("No Solution\n"); 641 | continue; 642 | }else if(dlx.solutionCount > 1) { 643 | // 数独多个解的情况 644 | printf("Multiple Solutions\n"); 645 | continue; 646 | } 647 | 648 | bool f = 0; 649 | for(i = 0; i < n*n; i++) { 650 | for(j = 0; j < n*n; j++) { 651 | if(sdkTemp[i][j] != '.') { 652 | char c = sdkTemp[i][j]; 653 | sdkTemp[i][j] = '.'; 654 | sdk.startSolveSudoku(n, EDT_JUDGE_MULTIPLE, sdkTemp); 655 | if(dlx.solutionCount == 1) { 656 | f = 1; 657 | } 658 | sdkTemp[i][j] = c; 659 | if(f) break; 660 | } 661 | } 662 | if(f) break; 663 | } 664 | if(f) { 665 | printf("Not Minimal\n"); 666 | }else { 667 | // 去掉任意一个元素,都会导致多个解的情况 668 | sdk.startSolveSudoku(n, EDT_GET_ONE_SOLUTION, sdkTemp); 669 | sdk.outputSDKMatrix(); 670 | } 671 | } 672 | return 0; 673 | } 674 | -------------------------------------------------------------------------------- /Dancing Links/Dancing Links 模板.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Dancing Links 高效搜索算法 3 | 1) 如果矩阵A没有列(即空矩阵),则当前记录的解为一个可行解;算法终止,成功返回; 4 | 2) 否则选择矩阵A中“1”的个数最少的列c;(确定性选择) 5 | 3) a.如果存在A[r][c]=1的行r,将行r放入可行解列表,进入步骤4);(非确定性选择) 6 | b.如果不存在A[r][c]=1的行r,则剩下的矩阵不可能完成精确覆盖,说明之前的选择有错(或者根本就无解),需要回溯,并且恢复此次删除的行和列,然后跳到步骤3)a; 7 | 4)对于所有的满足A[r][j]=1的列j 8 | 对于所有满足A[i][j]=1的行i,将行i从矩阵A中删除; 9 | 将列j从矩阵A中删除; 10 | 5) 在不断减少的矩阵A上递归重复调用上述算法; 11 | 12 | Author: WhereIsHeroFrom 13 | Update Time: 2018-3-21 14 | Algorithm Complexity: NP 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | using namespace std; 22 | 23 | #define MAXR 510 24 | #define MAXC 920 25 | #define MAXB 62 26 | #define MAXROWCODE ((MAXC+MAXB-1)/MAXB) 27 | #define INF -1 28 | #define INT64 long long 29 | 30 | enum eCoverType { 31 | ECT_EXACT = 0, // 精确覆盖 32 | ECT_REPEAT = 1, // 重复覆盖 33 | }; 34 | 35 | /* 36 | DLXNode 37 | left, right 十字交叉双向循环链表的左右指针 38 | up, down 十字交叉双向循环链表的上下指针 39 | 40 | <用于列首结点> 41 | colSum 列的结点总数 42 | colIdx 列的编号 43 | 44 | <用于行首结点/元素结点> 45 | colHead 指向列首结点的指针 46 | rowIdx DLXNode结点在原矩阵中的行标号 47 | */ 48 | class DLXNode { 49 | public: 50 | DLXNode *left, *right, *up, *down; 51 | union { 52 | struct { 53 | DLXNode *colHead; 54 | int rowIdx; 55 | }node; 56 | struct { 57 | int colIdx; 58 | int colSum; 59 | }col; 60 | }data; 61 | public: 62 | ////////////////////////////////////////////////////////// 63 | // 获取/设置 接口 64 | void resetCol(int colIdx); 65 | void resetColSum(); 66 | void updateColSum(int delta); 67 | int getColSum(); 68 | 69 | void setColIdx(int colIdx); 70 | int getColIdx(); 71 | 72 | void setColHead(DLXNode *colPtr); 73 | DLXNode *getColHead(); 74 | 75 | void setRowIdx(int rowIdx); 76 | int getRowIdx(); 77 | 78 | /////////////////////////////////////////////////////////// 79 | // 搜索求解用到的接口 80 | void appendToCol(DLXNode *colPtr); 81 | void appendToRow(DLXNode *rowPtr); 82 | 83 | void deleteFromCol(); 84 | void resumeFromCol(); 85 | 86 | void deleteFromRow(); 87 | void resumeFromRow(); 88 | /////////////////////////////////////////////////////////// 89 | }; 90 | 91 | void DLXNode::resetCol(int colIdx) { 92 | // IDA*的时候需要用到列下标进行hash 93 | setColIdx(colIdx); 94 | // 初始化每列结点个数皆为0 95 | resetColSum(); 96 | } 97 | void DLXNode::resetColSum() { 98 | data.col.colSum = 0; 99 | } 100 | 101 | void DLXNode::updateColSum(int delta) { 102 | data.col.colSum += delta; 103 | } 104 | 105 | int DLXNode::getColSum() { 106 | return data.col.colSum; 107 | } 108 | 109 | void DLXNode::setColIdx(int colIdx) { 110 | data.col.colIdx = colIdx; 111 | } 112 | int DLXNode::getColIdx() { 113 | return data.col.colIdx; 114 | } 115 | 116 | void DLXNode::setColHead(DLXNode * colPtr) { 117 | data.node.colHead = colPtr; 118 | } 119 | 120 | DLXNode* DLXNode::getColHead() { 121 | return data.node.colHead; 122 | } 123 | 124 | void DLXNode::setRowIdx(int rowIdx) { 125 | data.node.rowIdx = rowIdx; 126 | } 127 | 128 | int DLXNode::getRowIdx() { 129 | return data.node.rowIdx; 130 | } 131 | 132 | void DLXNode::appendToCol(DLXNode * colPtr) { 133 | // 赋值列首指针 134 | setColHead(colPtr); 135 | 136 | // 这几句要求插入结点顺序保证列递增,否则会导致乱序(每次插在一列的最后) 137 | up = colPtr->up; 138 | down = colPtr; 139 | colPtr->up = colPtr->up->down = this; 140 | 141 | // 列元素++ 142 | colPtr->updateColSum(1); 143 | } 144 | 145 | void DLXNode::appendToRow(DLXNode* rowPtr) { 146 | // 赋值行编号 147 | setRowIdx(rowPtr->getRowIdx()); 148 | 149 | // 这几句要求插入结点顺序保证行递增(每次插在一行的最后) 150 | left = rowPtr->left; 151 | right = rowPtr; 152 | rowPtr->left = rowPtr->left->right = this; 153 | } 154 | 155 | void DLXNode::deleteFromCol() { 156 | left->right = right; 157 | right->left = left; 158 | } 159 | 160 | void DLXNode::resumeFromCol() { 161 | right->left = left->right = this; 162 | } 163 | 164 | void DLXNode::deleteFromRow() { 165 | up->down = down; 166 | down->up = up; 167 | if (getColHead()) 168 | getColHead()->updateColSum(-1); 169 | } 170 | 171 | void DLXNode::resumeFromRow() { 172 | if (getColHead()) 173 | getColHead()->updateColSum(1); 174 | up->down = down->up = this; 175 | } 176 | 177 | /* 178 | DLX (单例) 179 | head head 只有左右(left、right)两个指针有效,指向列首 180 | rowCount, colCount 本次样例矩阵的规模(行列数) 181 | row[] 行首结点列表 182 | col[] 列首结点列表 183 | 184 | dlx_pool 结点对象池(配合dlx_pool_idx取对象) 185 | */ 186 | class DLX { 187 | DLXNode *head; // 总表头 188 | int rowCount, colCount; // 本次样例矩阵的规模(行列数) 189 | DLXNode *row, *col; // 行首结点列表 / 列首结点列表 190 | 191 | DLXNode *dlx_pool; // 结点对象池 192 | int dlx_pool_idx; // 结点对象池下标 193 | 194 | eCoverType eCType; 195 | int *col_coverd; // 标记第i列是否覆盖,避免重复覆盖 196 | INT64 *row_code; // 每行采用二进制标记进行优化 197 | int limitColCount; // 限制列的个数 198 | // 即 前 limitColCount 列满足每列1个"1",就算搜索结束 199 | // 一般情况下 limitColCount == colCount 200 | public: 201 | int *result, resultCount; // 结果数组 202 | int minResultCount; 203 | 204 | private: 205 | DLX() { 206 | dlx_pool_idx = 0; 207 | head = NULL; 208 | dlx_pool = new DLXNode[MAXR*MAXC]; 209 | col = new DLXNode[MAXC+1]; 210 | row = new DLXNode[MAXR]; 211 | result = new int[MAXR]; 212 | col_coverd = new int[MAXC+1]; 213 | row_code = new INT64[MAXR*MAXROWCODE]; 214 | } 215 | 216 | ~DLX() { 217 | delete [] dlx_pool; 218 | delete [] col; 219 | delete [] row; 220 | delete [] result; 221 | delete [] col_coverd; 222 | delete [] row_code; 223 | } 224 | 225 | void reset_size(int r, int c, int limitC = INF, eCoverType ect = ECT_EXACT) { 226 | rowCount = r; 227 | colCount = c; 228 | limitColCount = limitC != INF? limitC : c; 229 | eCType = ect; 230 | dlx_pool_idx = 0; 231 | resultCount = minResultCount = -1; 232 | } 233 | 234 | void reset_col(); 235 | void reset_row(); 236 | DLXNode* get_node(); 237 | DLXNode* get_min_col(); 238 | 239 | bool judgeRowCodeByCol(INT64 *rowCode, int colIdx); 240 | void updateRowCodeByCol(INT64 *rowCode, int colIdx); 241 | void updateRowCodeByRowCode(INT64 *rowCode, INT64 *srcRowCode); 242 | int get_eval(); // 估价函数 243 | 244 | void cover(DLXNode *colPtr); 245 | void uncover(DLXNode *colPtr); 246 | 247 | void coverRow(DLXNode *nodePtr); 248 | void uncoverRow(DLXNode *nodePtr); 249 | 250 | bool isEmpty(); 251 | public: 252 | 253 | void init(int r, int c, int limitC, eCoverType ect); 254 | void add(int rowIdx, int colIdx); // index 0-based 255 | void output(); 256 | bool dance(int depth, int maxDepth); 257 | void preCoverRow(int rowIndex); 258 | 259 | static DLX& Instance() { 260 | static DLX inst; 261 | return inst; 262 | } 263 | }; 264 | 265 | void DLX::reset_col() { 266 | // [0, colCount)作为列首元素, 267 | // 第colCount个列首元素的地址作为总表头head 268 | for(int i = 0; i <= colCount; ++i) { 269 | DLXNode *colPtr = &col[i]; 270 | colPtr->resetCol(i); 271 | // 初始化,每列元素为空,所以列首指针上下循环指向自己 272 | colPtr->up = colPtr->down = colPtr; 273 | // 第i个元素指向第i-1个,当i==0,则指向第colCount个,构成循环 274 | colPtr->left = &col[(i+colCount)%(colCount+1)]; 275 | // 第i个元素指向第i+1个,当i==colCount,则指向第0个,构成循环 276 | colPtr->right = &col[(i+1)%(colCount+1)]; 277 | col_coverd[i] = 0; 278 | } 279 | // 取第colCount个列首元素的地址作为总表头 280 | head = &col[colCount]; 281 | } 282 | 283 | void DLX::reset_row() { 284 | for(int i = 0; i < rowCount; ++i) { 285 | // 初始化行首结点 286 | DLXNode *rowPtr = &row[i]; 287 | // 初始化行,每行都为空,所以结点的各个指针都指向自己 288 | rowPtr->left = rowPtr->right = rowPtr->up = rowPtr->down = rowPtr; 289 | // 对应cover时候的函数入口的非空判断 290 | rowPtr->setColHead(NULL); 291 | rowPtr->setRowIdx(i); 292 | for(int j = 0; j < MAXROWCODE; ++j) { 293 | row_code[i*MAXROWCODE + j] = 0; 294 | } 295 | } 296 | } 297 | 298 | DLXNode* DLX::get_node() { 299 | return &dlx_pool[dlx_pool_idx++]; 300 | } 301 | 302 | void DLX::init(int r, int c, int limitC, eCoverType ect) { 303 | reset_size(r, c, limitC, ect); 304 | reset_row(); 305 | reset_col(); 306 | } 307 | 308 | DLXNode* DLX::get_min_col() { 309 | DLXNode *resPtr = head->right; 310 | for(DLXNode *ptr = resPtr->right; ptr != head; ptr = ptr->right) { 311 | if(ptr->getColIdx() >= limitColCount) 312 | break; 313 | if(ptr->getColSum() < resPtr->getColSum()) { 314 | resPtr = ptr; 315 | } 316 | } 317 | return resPtr; 318 | } 319 | 320 | bool DLX::judgeRowCodeByCol(INT64 *rowCode, int colIdx) { 321 | int i; 322 | for(i = 0; i < MAXROWCODE; i++) { 323 | if(i*MAXB <= colIdx && colIdx < (i+1)*MAXB) { 324 | colIdx -= i*MAXB; 325 | return (rowCode[i] & ((INT64)1< 0; 326 | } 327 | } 328 | return false; 329 | } 330 | 331 | void DLX::updateRowCodeByCol(INT64 *rowCode, int colIdx) { 332 | int i; 333 | for(i = 0; i < MAXROWCODE; i++) { 334 | if(i*MAXB <= colIdx && colIdx < (i+1)*MAXB) { 335 | colIdx -= i*MAXB; 336 | rowCode[i] |= ((INT64)1<right; colPtr != head; colPtr = colPtr->right) { 361 | int colIdx = colPtr->getColIdx(); 362 | if(!judgeRowCodeByCol(rowCode, colIdx)) { 363 | updateRowCodeByCol(rowCode, colIdx); 364 | ++eval; 365 | // 枚举该列上的么个元素 366 | for(DLXNode *nodePtr = colPtr->down; nodePtr != colPtr; nodePtr = nodePtr->down) { 367 | updateRowCodeByRowCode(rowCode, &row_code[nodePtr->getRowIdx()*MAXROWCODE]); 368 | } 369 | } 370 | } 371 | return eval; 372 | } 373 | 374 | /* 375 | 功能:插入一个(rowIdx, colIdx)的结点(即原01矩阵中(rowIdx, colIdx)位置为1的) 376 | 注意:按照行递增、列递增的顺序进行插入 377 | */ 378 | void DLX::add(int rowIdx, int colIdx) { 379 | DLXNode *nodePtr = get_node(); 380 | // 将结点插入到对应列尾 381 | nodePtr->appendToCol(&col[colIdx]); 382 | // 将结点插入到对应行尾 383 | nodePtr->appendToRow(&row[rowIdx]); 384 | updateRowCodeByCol(&row_code[MAXROWCODE*rowIdx], colIdx); 385 | } 386 | 387 | /* 388 | 功能:输出当前矩阵 389 | 调试神器 390 | */ 391 | void DLX::output() { 392 | for(int i = 0; i < rowCount; i++) { 393 | DLXNode *rowPtr = &row[i]; 394 | printf("row(%d)", i); 395 | for(DLXNode *nodePtr = rowPtr->right; nodePtr != rowPtr; nodePtr = nodePtr->right) { 396 | printf(" [%d]", nodePtr->getColHead()->getColIdx()); 397 | } 398 | puts(""); 399 | } 400 | } 401 | 402 | /* 403 | 功能:删除行 404 | 精确覆盖在删除列的时候,需要对行进行删除处理 405 | 枚举每个和nodePtr在同一行的结点p,执行删除操作 406 | */ 407 | void DLX::coverRow(DLXNode* nodePtr) { 408 | for(DLXNode *p = nodePtr->right; p != nodePtr; p = p->right) { 409 | p->deleteFromRow(); 410 | } 411 | } 412 | 413 | /* 414 | 功能:恢复行 415 | coverRow的逆操作 416 | */ 417 | void DLX::uncoverRow(DLXNode* nodePtr) { 418 | for(DLXNode *p = nodePtr->left; p != nodePtr; p = p->left) { 419 | p->resumeFromRow(); 420 | } 421 | } 422 | 423 | /* 424 | 功能:覆盖colPtr指向的那一列 425 | 说是覆盖,其实是删除那一列。 426 | 如果是精确覆盖,需要删除那列上所有结点对应的行,原因是,cover代表我会选择这列,这列上有1的行必须都删除 427 | */ 428 | void DLX::cover(DLXNode *colPtr) { 429 | if(!colPtr) { 430 | return; 431 | } 432 | if(!col_coverd[colPtr->getColIdx()]) { 433 | // 删除colPtr指向的那一列 434 | colPtr->deleteFromCol(); 435 | // 枚举每个在colPtr对应列上的结点p 436 | if (eCType == ECT_EXACT) { 437 | for(DLXNode* nodePtr = colPtr->down; nodePtr != colPtr; nodePtr = nodePtr->down) { 438 | coverRow(nodePtr); 439 | } 440 | } 441 | } 442 | ++col_coverd[colPtr->getColIdx()]; 443 | } 444 | 445 | /* 446 | 功能:恢复colPtr指向的那一列 447 | cover的逆操作 448 | */ 449 | void DLX::uncover(DLXNode* colPtr) { 450 | if(!colPtr) { 451 | return; 452 | } 453 | --col_coverd[colPtr->getColIdx()]; 454 | if(!col_coverd[colPtr->getColIdx()]) { 455 | // 枚举每个在colPtr对应列上的结点p 456 | if (eCType == ECT_EXACT) { 457 | for(DLXNode* nodePtr = colPtr->up; nodePtr != colPtr; nodePtr = nodePtr->up) { 458 | uncoverRow(nodePtr); 459 | } 460 | } 461 | // 恢复colPtr指向的那一列 462 | colPtr->resumeFromCol(); 463 | } 464 | } 465 | 466 | /* 467 | 功能:用于预先选择某行 468 | */ 469 | void DLX::preCoverRow(int rowIndex) { 470 | DLXNode *rowPtr = &row[rowIndex]; 471 | for(DLXNode *p = rowPtr->right; p != rowPtr; p = p->right) { 472 | cover(p->getColHead()); 473 | } 474 | } 475 | 476 | bool DLX::isEmpty() { 477 | if(head->right == head) { 478 | return true; 479 | } 480 | return head->right->getColIdx() >= limitColCount; 481 | } 482 | 483 | bool DLX::dance(int depth, int maxDepth=INF) { 484 | if(minResultCount != -1 && depth > minResultCount) { 485 | return false; 486 | } 487 | // 当前矩阵为空,说明找到一个可行解,算法终止 488 | if(isEmpty()) { 489 | resultCount = depth; 490 | if(minResultCount == -1 || resultCount < minResultCount) { 491 | minResultCount = resultCount; 492 | } 493 | return false; 494 | } 495 | if (maxDepth != INF) { 496 | if(depth + get_eval() > maxDepth) { 497 | return false; 498 | } 499 | } 500 | 501 | DLXNode *minPtr = get_min_col(); 502 | // 删除minPtr指向的列 503 | cover(minPtr); 504 | // minPtr为结点数最少的列,枚举这列上所有的行 505 | for(DLXNode *p = minPtr->down; p != minPtr; p = p->down) { 506 | // 令r = p->getRowIdx(),行r放入当前解 507 | result[depth] = p->getRowIdx(); 508 | // 行r上的结点对应的列进行删除 509 | for(DLXNode *q = p->right; q != p; q = q->right) { 510 | cover(q->getColHead()); 511 | } 512 | // 进入搜索树的下一层 513 | if(dance(depth+1, maxDepth)) { 514 | return true; 515 | } 516 | // 行r上的结点对应的列进行恢复 517 | for(DLXNode *q = p->left; q != p; q = q->left) { 518 | uncover(q->getColHead()); 519 | } 520 | } 521 | // 恢复minPtr指向的列 522 | uncover(minPtr); 523 | return false; 524 | } 525 | 526 | #define MAXN 35 527 | int rowCnt, colCnt; 528 | int colIdx[MAXN][MAXN]; 529 | int dlx_mat[MAXR][MAXC]; 530 | 531 | int X, Y, p; 532 | 533 | int main() { 534 | int t; 535 | int i, j; 536 | scanf("%d", &t); 537 | while(t--) { 538 | scanf("%d %d %d", &X, &Y, &p); 539 | colCnt = 0; 540 | for(i = 0; i < X; ++i) { 541 | for(j = 0; j < Y; ++j) { 542 | colIdx[i][j] = colCnt++; 543 | } 544 | } 545 | memset(dlx_mat, 0, sizeof(dlx_mat)); 546 | rowCnt = p; 547 | for(i = 0; i < p; i++) { 548 | int x1, y1, x2, y2; 549 | scanf("%d %d %d %d", &x1, &y1, &x2, &y2); 550 | for(int x = x1; x < x2; ++x) { 551 | for(int y = y1; y < y2; ++y) { 552 | dlx_mat[i][ colIdx[x][y] ] = 1; 553 | } 554 | } 555 | } 556 | DLX &dlx = DLX::Instance(); 557 | dlx.init(rowCnt, colCnt, INF, ECT_EXACT); 558 | for(i = 0; i < rowCnt; ++i) { 559 | for(j = 0; j < colCnt; ++j) { 560 | if(dlx_mat[i][j]) { 561 | dlx.add(i, j); 562 | //printf("<%d, %d>\n", i, j); 563 | } 564 | } 565 | } 566 | dlx.dance(0); 567 | printf("%d\n", dlx.minResultCount); 568 | } 569 | return 0; 570 | } 571 | -------------------------------------------------------------------------------- /HASH/字符串哈希 模板.c: -------------------------------------------------------------------------------- 1 | #define ull unsigned long long 2 | #define maxn 100010 3 | #define P 10207 4 | ull h[maxn], p[maxn]; 5 | 6 | void initHash(const char *s) { 7 | // 这个字符串是从 1 - n-1 8 | int n = strlen(s); 9 | int i; 10 | p[0] = 1; 11 | h[0] = 0; 12 | for(i = 1; i < n; ++i) { 13 | h[i] = h[i-1] * P + s[i]; 14 | p[i] = p[i-1] * P; 15 | } 16 | } 17 | 18 | ull getSubHash(int l, int r) { 19 | return h[r] - h[l-1] * p[r - l + 1]; 20 | } 21 | -------------------------------------------------------------------------------- /HASH/字符串哈希 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/HASH/字符串哈希 模板.cpp -------------------------------------------------------------------------------- /HASH/散列HASH 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/HASH/散列HASH 模板.cpp -------------------------------------------------------------------------------- /HASH/整数哈希 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/HASH/整数哈希 模板.cpp -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 微信搜索「夜深人静写算法」或者扫一扫二维码,回复关键字,获取更多资料。 2 | 3 | ![](https://img-blog.csdnimg.cn/20210105190605774.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1doZXJlSXNIZXJvRnJvbQ==,size_16,color_FFFFFF,t_70) 4 | 5 | github地址: 6 | https://github.com/WhereIsHeroFrom/Code_Templates -------------------------------------------------------------------------------- /RMQ/RMQ_1D 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/RMQ/RMQ_1D 模板.cpp -------------------------------------------------------------------------------- /RMQ/RMQ_2D 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/RMQ/RMQ_2D 模板.cpp -------------------------------------------------------------------------------- /RMQ/RMQ_GCD 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/RMQ/RMQ_GCD 模板.cpp -------------------------------------------------------------------------------- /《夜深人静写算法》.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/《夜深人静写算法》.png -------------------------------------------------------------------------------- /动态规划/dp单调队列 最大K子串 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/动态规划/dp单调队列 最大K子串 模板.cpp -------------------------------------------------------------------------------- /动态规划/dp斜率优化 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/动态规划/dp斜率优化 模板.cpp -------------------------------------------------------------------------------- /动态规划/dp斜率优化(2D) 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/动态规划/dp斜率优化(2D) 模板.cpp -------------------------------------------------------------------------------- /动态规划/单调队列 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/动态规划/单调队列 模板.cpp -------------------------------------------------------------------------------- /动态规划/数位 DP 模板.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | const int maxl = 20; 10 | const int invalidstate = -123456789; 11 | const int saturatedstate = 10; 12 | const int leadingzerostate = 11; 13 | const int maxstate = leadingzerostate + 1; 14 | const int base = 10; 15 | const int inf = -1; 16 | #define ll long long 17 | #define stType int 18 | ll f[maxl][maxstate]; 19 | 20 | bool isEndStateValid(stType state) { 21 | return (state == 0) || (state == leadingzerostate); 22 | } 23 | 24 | stType nextState(stType st, int digit) { 25 | if(st == leadingzerostate) { 26 | if(digit == 0) { 27 | return leadingzerostate; 28 | } 29 | st = 0; 30 | } 31 | return (st + digit) % 10; 32 | } 33 | 34 | void init() { 35 | memset(f, inf, sizeof(f)); 36 | } 37 | 38 | ll dfs(int n, stType state, bool lim, int d[]) { 39 | if(n == 0) 40 | return isEndStateValid(state) ? 1 : 0; 41 | ll sum = f[n][state]; 42 | if(lim && sum != inf) return sum; 43 | sum = 0; 44 | int maxv = lim ? base - 1 : d[n]; 45 | for(int k = 0; k <= maxv; ++k) { 46 | stType st = nextState(state, k); 47 | bool nextlim = (k < maxv) || lim; 48 | if(invalidstate != st) 49 | sum += dfs(n-1, st, nextlim, d); 50 | } 51 | if(lim) f[n][state] = sum; 52 | return sum; 53 | } 54 | 55 | ll g(ll x) { 56 | if (x < 0) return 0; 57 | if (x == 0) return 1; 58 | int d[maxl]; 59 | int n = 0; 60 | while (x) { 61 | d[++n] = x % base; 62 | x /= base; 63 | } 64 | return dfs(n, leadingzerostate, false, d); 65 | } 66 | 67 | int main() { 68 | int t, cas = 0; 69 | init(); 70 | ll a, b; 71 | scanf("%d", &t); 72 | while (t--) { 73 | scanf("%lld %lld", &a, &b); 74 | printf("Case #%d: %lld\n", ++cas, g(b) - g(a - 1)); 75 | } 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /动态规划/最大完全子矩阵 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/动态规划/最大完全子矩阵 模板.cpp -------------------------------------------------------------------------------- /动态规划/最小编辑距离/Levenshtein 路径回溯.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/动态规划/最小编辑距离/Levenshtein 路径回溯.cpp -------------------------------------------------------------------------------- /动态规划/最小编辑距离/Levenshtein.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/动态规划/最小编辑距离/Levenshtein.cpp -------------------------------------------------------------------------------- /动态规划/最长公共子序列/最长公共子序列 优化版.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/动态规划/最长公共子序列/最长公共子序列 优化版.cpp -------------------------------------------------------------------------------- /动态规划/最长公共子序列/最长公共子序列 模板.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | typedef char ValueType; 7 | const int maxn = 2010; 8 | int f[maxn][maxn]; 9 | 10 | int getLCS(int hsize, ValueType *h, int vsize, ValueType *v) { 11 | memset(f, 0, sizeof(f)); 12 | f[0][0] = 0; 13 | for (int i = 1; i <= vsize; ++i) { 14 | for (int j = 1; j <= hsize; ++j) { 15 | if (v[i] == h[j]) { 16 | f[i][j] = f[i - 1][j - 1] + 1; 17 | } 18 | else { 19 | f[i][j] = max(f[i - 1][j], f[i][j - 1]); 20 | } 21 | } 22 | } 23 | return f[vsize][hsize]; 24 | } 25 | 26 | char s[2][maxn]; 27 | 28 | int main() { 29 | int len[2]; 30 | while (scanf("%s %s", &s[0][1], &s[1][1]) != EOF) { 31 | len[0] = strlen(&s[0][1]); 32 | len[1] = strlen(&s[1][1]); 33 | printf("%d\n", getLCS(len[0], s[0], len[1], s[1])); 34 | 35 | } 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /动态规划/最长公共子序列/最长公共子序列 路径回溯 模板.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | typedef char ValueType; 8 | const int maxn = 1010; 9 | int f[2][maxn]; 10 | int p[maxn][maxn]; 11 | 12 | int pack(int x, int y) { 13 | return x * maxn + y; 14 | } 15 | 16 | int getLCSLength(int hsize, ValueType *h, int vsize, ValueType *v, stack& path) { 17 | memset(f, 0, sizeof(f)); 18 | while (!path.empty()) 19 | path.pop(); 20 | int cur = 1, last = 0; 21 | for (int i = 1; i <= vsize; ++i) { 22 | for (int j = 1; j <= hsize; ++j) { 23 | if (v[i] == h[j]) { 24 | f[cur][j] = f[last][j - 1] + 1; 25 | p[i][j] = pack(i - 1, j - 1); 26 | } 27 | else { 28 | f[cur][j] = max(f[last][j], f[cur][j - 1]); 29 | p[i][j] = f[last][j] > f[cur][j - 1] ? pack(i - 1, j) : pack(i, j - 1); 30 | } 31 | } 32 | swap(last, cur); 33 | } 34 | int vidx = vsize, hidx = hsize; 35 | while (vidx && hidx) { 36 | int pre = p[vidx][hidx]; 37 | int previdx = pre / maxn; 38 | int prehidx = pre % maxn; 39 | if (vidx - previdx && prehidx - hidx) { 40 | path.push(vidx * maxn + hidx); 41 | } 42 | vidx = previdx; 43 | hidx = prehidx; 44 | } 45 | return f[last][hsize]; 46 | } 47 | -------------------------------------------------------------------------------- /动态规划/最长公共子序列/最长公共子序列(滚动数组) 模板.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | typedef char ValueType; 7 | const int maxn = 2010; 8 | int f[2][maxn]; 9 | 10 | int getLCS(int hsize, ValueType *h, int vsize, ValueType *v) { 11 | memset(f, 0, sizeof(f)); 12 | int cur = 1, last = 0; 13 | for (int i = 1; i <= vsize; ++i) { 14 | for (int j = 1; j <= hsize; ++j) { 15 | if (v[i] == h[j]) { 16 | f[cur][j] = f[last][j - 1] + 1; 17 | } 18 | else { 19 | f[cur][j] = max(f[last][j], f[cur][j - 1]); 20 | } 21 | } 22 | swap(last, cur); 23 | } 24 | return f[last][hsize]; 25 | } 26 | 27 | char s[2][maxn]; 28 | 29 | int main() { 30 | int len[2]; 31 | while (scanf("%s %s", &s[0][1], &s[1][1]) != EOF) { 32 | len[0] = strlen(&s[0][1]); 33 | len[1] = strlen(&s[1][1]); 34 | printf("%d\n", getLCS(len[0], s[0], len[1], s[1])); 35 | 36 | } 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /动态规划/最长公共子序列/最长公共递增子序列 模板.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | typedef int ValueType; 8 | const int maxn = 1010; 9 | int f[2][maxn]; 10 | int p[maxn][maxn]; 11 | 12 | int pack(int x, int y) { 13 | return x * maxn + y; 14 | } 15 | 16 | int getLCSLength(int hsize, ValueType *h, int vsize, ValueType *v, stack& path) { 17 | 18 | memset(f, 0, sizeof(f)); 19 | while (!path.empty()) 20 | path.pop(); 21 | 22 | int cur = 1, last = 0; 23 | for (int i = 1; i <= vsize; ++i) { 24 | int opt = 0, pos = 0; 25 | for (int j = 1; j <= hsize; ++j) { 26 | if (v[i] > h[j]) { 27 | opt = max(opt, f[last][j]); 28 | if (opt == f[last][j]) { 29 | pos = j; 30 | } 31 | } 32 | 33 | if (v[i] == h[j]) { 34 | f[cur][j] = opt + 1; 35 | p[i][j] = pack(i - 1, pos); 36 | } 37 | else { 38 | f[cur][j] = f[last][j]; 39 | p[i][j] = pack(i - 1, j); 40 | } 41 | } 42 | swap(last, cur); 43 | } 44 | int vidx = vsize, hidx = hsize; 45 | int Max = -1; 46 | for (int i = 1; i <= hsize; ++i) { 47 | if (f[last][i] > Max) { 48 | Max = f[last][i]; 49 | hidx = i; 50 | } 51 | } 52 | 53 | 54 | while (vidx && hidx) { 55 | int pre = p[vidx][hidx]; 56 | int previdx = pre / maxn; 57 | int prehidx = pre % maxn; 58 | if (vidx - previdx && prehidx - hidx) { 59 | path.push(vidx * maxn + hidx); 60 | } 61 | vidx = previdx; 62 | hidx = prehidx; 63 | } 64 | return f[last][hsize]; 65 | } 66 | 67 | ValueType s[2][maxn]; 68 | 69 | int main() { 70 | int len[2], t; 71 | scanf("%d", &t); 72 | while (t--){ 73 | scanf("%d", &len[0]); 74 | for (int i = 1; i <= len[0]; ++i) { 75 | scanf("%d", &s[0][i]); 76 | } 77 | 78 | scanf("%d", &len[1]); 79 | for (int i = 1; i <= len[1]; ++i) { 80 | scanf("%d", &s[1][i]); 81 | } 82 | stack path; 83 | getLCSLength(len[0], s[0], len[1], s[1], path); 84 | 85 | printf("%d\n", path.size()); 86 | if (t) puts(""); 87 | } 88 | return 0; 89 | } 90 | -------------------------------------------------------------------------------- /动态规划/最长单调子序列.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/动态规划/最长单调子序列.cpp -------------------------------------------------------------------------------- /动态规划/背包问题/01背包 K优解 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/动态规划/背包问题/01背包 K优解 模板.cpp -------------------------------------------------------------------------------- /动态规划/背包问题/01背包 模板(滚动数组).cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/动态规划/背包问题/01背包 模板(滚动数组).cpp -------------------------------------------------------------------------------- /动态规划/背包问题/01背包 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/动态规划/背包问题/01背包 模板.cpp -------------------------------------------------------------------------------- /动态规划/背包问题/主件附件依赖背包 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/动态规划/背包问题/主件附件依赖背包 模板.cpp -------------------------------------------------------------------------------- /动态规划/背包问题/二维 01背包 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/动态规划/背包问题/二维 01背包 模板.cpp -------------------------------------------------------------------------------- /动态规划/背包问题/分组背包 (最多一个) 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/动态规划/背包问题/分组背包 (最多一个) 模板.cpp -------------------------------------------------------------------------------- /动态规划/背包问题/分组背包 (至少一个) 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/动态规划/背包问题/分组背包 (至少一个) 模板.cpp -------------------------------------------------------------------------------- /动态规划/背包问题/多重背包 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/动态规划/背包问题/多重背包 模板.cpp -------------------------------------------------------------------------------- /动态规划/背包问题/完全背包 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/动态规划/背包问题/完全背包 模板.cpp -------------------------------------------------------------------------------- /动态规划/背包问题/树上分组背包 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/动态规划/背包问题/树上分组背包 模板.cpp -------------------------------------------------------------------------------- /图论/二分图/二分图最大匹配 邻接表.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/二分图/二分图最大匹配 邻接表.cpp -------------------------------------------------------------------------------- /图论/二分图/二分图最大匹配 链式前向星.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/二分图/二分图最大匹配 链式前向星.cpp -------------------------------------------------------------------------------- /图论/差分约束模板.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 差分约束系统 3 | 将数学的不等式转化成图论中的边,然后求最长路或最短路。 4 | 增加一条限制条件: 5 | a - b >= c 6 | if(b + c > a) { 7 | a = b + c; 8 | // 则进行更新,此为求最长路的条件 9 | } 10 | 这表示b经过c这条边能够到达a,则建边如下:b->a(权为c) 11 | Author: WhereIsHeroFrom 12 | Update Time: 2018-3-21 13 | Algorithm Complexity: O(n+m) 14 | */ 15 | 16 | 17 | 18 | #include 19 | #include 20 | 21 | using namespace std; 22 | 23 | #define MAXN 50010 24 | #define MAXE 1000020 25 | #define INF 100000000 26 | 27 | /* 28 | 有向带权边 29 | */ 30 | class Edge { 31 | public: 32 | int edgeValue; 33 | int toVertex; 34 | Edge* next; 35 | 36 | Edge() {} 37 | void reset(int _to, int _val, Edge* _next) { 38 | toVertex = _to; 39 | edgeValue = _val; 40 | next = _next; 41 | } 42 | }; 43 | typedef Edge* EdgePtr; 44 | 45 | /* 46 | 有向图 47 | */ 48 | class Graph { 49 | EdgePtr *head; 50 | Edge *edges; 51 | int edgeCount; 52 | int vertexCount; 53 | 54 | Graph() { 55 | // 链式前向星 存储 56 | // 邻接表首结点 57 | head = new EdgePtr[MAXN]; 58 | // 距离 59 | dist = new int[MAXN]; 60 | // 顶点访问次数 61 | visit = new int[MAXN]; 62 | // 边内存池 63 | edges = new Edge[MAXE]; 64 | } 65 | ~Graph() { 66 | delete [] edges; 67 | delete [] head; 68 | delete [] dist; 69 | delete [] visit; 70 | } 71 | public: 72 | int *visit; 73 | int *dist; 74 | 75 | void init(int vCount); 76 | void initDist(); 77 | void addConstraint(int a, int b, int c); 78 | void addEdge(int from, int to, int value); 79 | bool spfa(int start); 80 | 81 | static Graph& Instance() { 82 | static Graph inst; 83 | return inst; 84 | } 85 | }; 86 | 87 | void Graph::init(int vCount) { 88 | vertexCount = vCount; 89 | edgeCount = 0; 90 | for(int i = 0; i <= vCount; i++) { 91 | head[i] = NULL; 92 | } 93 | } 94 | 95 | /* 96 | 增加一条限制条件: 97 | a - b >= c 98 | if(b + c > a) { 99 | a = b + c; 100 | // 则进行更新,此为求最长路的条件 101 | } 102 | 这表示b经过c这条边能够到达a,则建边如下:b->a(权为c) 103 | */ 104 | 105 | void Graph::addConstraint(int a, int b, int c) { 106 | //printf("%d-%d>=%d\n", a, b, c); 107 | addEdge(b, a, c); 108 | } 109 | 110 | void Graph::addEdge(int from, int to, int value) { 111 | edges[edgeCount].reset(to, value, head[from]); 112 | head[from] = &edges[edgeCount++]; 113 | } 114 | 115 | void Graph::initDist() { 116 | for(int i = 0; i <= vertexCount; ++i) { 117 | dist[i] = -INF; 118 | visit[i] = 0; 119 | } 120 | } 121 | 122 | bool Graph::spfa(int start) { 123 | int i; 124 | Edge *e; 125 | dist[start] = 1; 126 | visit[start] = 1; 127 | queue Q; 128 | Q.push(start); 129 | while( !Q.empty() ) { 130 | int u = Q.front(); 131 | Q.pop(); 132 | if( visit[u]++ > vertexCount + 1) { 133 | return false; 134 | } 135 | 136 | for(e = head[u]; e; e = e->next) { 137 | int &v = e->toVertex; 138 | int &val = e->edgeValue; 139 | if( dist[u] + val > dist[v] ) { 140 | dist[v] = dist[u] + val; 141 | Q.push(v); 142 | } 143 | } 144 | } 145 | return true; 146 | } 147 | -------------------------------------------------------------------------------- /图论/并查集/并查集 判奇环.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/并查集/并查集 判奇环.cpp -------------------------------------------------------------------------------- /图论/并查集/并查集 求解方程组合法性.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/并查集/并查集 求解方程组合法性.cpp -------------------------------------------------------------------------------- /图论/并查集/并查集 路径压缩.cpp: -------------------------------------------------------------------------------- 1 | const int MAXN = 300010; 2 | int fset[MAXN]; 3 | 4 | void init_set(int n) { 5 | for (int i = 1; i <= n; ++i) { 6 | fset[i] = i; 7 | } 8 | } 9 | 10 | int find_set(int x) { 11 | return (fset[x] == x) ? x : (fset[x] = find_set(fset[x])); 12 | } 13 | 14 | bool union_set(int x, int y) { 15 | int fx = find_set(x); 16 | int fy = find_set(y); 17 | if (fx != fy) { 18 | fset[fx] = fy; 19 | return true; 20 | } 21 | return false; 22 | } 23 | -------------------------------------------------------------------------------- /图论/广度优先搜索/PushBoxGame/PushBoxGame.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.40629.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PushBoxGame", "PushBoxGame\PushBoxGame.vcxproj", "{86C09603-84BA-457D-BB4D-056BBD9BC2E2}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Release|Win32 = Release|Win32 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {86C09603-84BA-457D-BB4D-056BBD9BC2E2}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {86C09603-84BA-457D-BB4D-056BBD9BC2E2}.Debug|Win32.Build.0 = Debug|Win32 16 | {86C09603-84BA-457D-BB4D-056BBD9BC2E2}.Release|Win32.ActiveCfg = Release|Win32 17 | {86C09603-84BA-457D-BB4D-056BBD9BC2E2}.Release|Win32.Build.0 = Release|Win32 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /图论/广度优先搜索/PushBoxGame/PushBoxGame.v12.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/广度优先搜索/PushBoxGame/PushBoxGame.v12.suo -------------------------------------------------------------------------------- /图论/广度优先搜索/PushBoxGame/PushBoxGame/Mission/1.x: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/广度优先搜索/PushBoxGame/PushBoxGame/Mission/1.x -------------------------------------------------------------------------------- /图论/广度优先搜索/PushBoxGame/PushBoxGame/Mission/10.x: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/广度优先搜索/PushBoxGame/PushBoxGame/Mission/10.x -------------------------------------------------------------------------------- /图论/广度优先搜索/PushBoxGame/PushBoxGame/Mission/11.x: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/广度优先搜索/PushBoxGame/PushBoxGame/Mission/11.x -------------------------------------------------------------------------------- /图论/广度优先搜索/PushBoxGame/PushBoxGame/Mission/2.x: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/广度优先搜索/PushBoxGame/PushBoxGame/Mission/2.x -------------------------------------------------------------------------------- /图论/广度优先搜索/PushBoxGame/PushBoxGame/Mission/3.x: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/广度优先搜索/PushBoxGame/PushBoxGame/Mission/3.x -------------------------------------------------------------------------------- /图论/广度优先搜索/PushBoxGame/PushBoxGame/Mission/4.x: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/广度优先搜索/PushBoxGame/PushBoxGame/Mission/4.x -------------------------------------------------------------------------------- /图论/广度优先搜索/PushBoxGame/PushBoxGame/Mission/5.x: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/广度优先搜索/PushBoxGame/PushBoxGame/Mission/5.x -------------------------------------------------------------------------------- /图论/广度优先搜索/PushBoxGame/PushBoxGame/Mission/6.x: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/广度优先搜索/PushBoxGame/PushBoxGame/Mission/6.x -------------------------------------------------------------------------------- /图论/广度优先搜索/PushBoxGame/PushBoxGame/Mission/7.x: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/广度优先搜索/PushBoxGame/PushBoxGame/Mission/7.x -------------------------------------------------------------------------------- /图论/广度优先搜索/PushBoxGame/PushBoxGame/Mission/8.x: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/广度优先搜索/PushBoxGame/PushBoxGame/Mission/8.x -------------------------------------------------------------------------------- /图论/广度优先搜索/PushBoxGame/PushBoxGame/Mission/9.x: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/广度优先搜索/PushBoxGame/PushBoxGame/Mission/9.x -------------------------------------------------------------------------------- /图论/广度优先搜索/PushBoxGame/PushBoxGame/PushBoxGame.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {86C09603-84BA-457D-BB4D-056BBD9BC2E2} 15 | Win32Proj 16 | PushBoxGame 17 | 18 | 19 | 20 | Application 21 | true 22 | v120 23 | Unicode 24 | 25 | 26 | Application 27 | false 28 | v120 29 | true 30 | Unicode 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | 45 | 46 | false 47 | 48 | 49 | 50 | 51 | 52 | Level3 53 | Disabled 54 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 55 | 56 | 57 | Console 58 | true 59 | 60 | 61 | 62 | 63 | Level3 64 | 65 | 66 | MaxSpeed 67 | true 68 | true 69 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 70 | 71 | 72 | Console 73 | true 74 | true 75 | true 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /图论/广度优先搜索/PushBoxGame/PushBoxGame/PushBoxGame.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | 35 | 36 | Header Files 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files 43 | 44 | 45 | Header Files 46 | 47 | 48 | Header Files 49 | 50 | 51 | -------------------------------------------------------------------------------- /图论/广度优先搜索/PushBoxGame/PushBoxGame/commondef.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/广度优先搜索/PushBoxGame/PushBoxGame/commondef.h -------------------------------------------------------------------------------- /图论/广度优先搜索/PushBoxGame/PushBoxGame/hash.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/广度优先搜索/PushBoxGame/PushBoxGame/hash.cpp -------------------------------------------------------------------------------- /图论/广度优先搜索/PushBoxGame/PushBoxGame/hash.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/广度优先搜索/PushBoxGame/PushBoxGame/hash.h -------------------------------------------------------------------------------- /图论/广度优先搜索/PushBoxGame/PushBoxGame/main.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/广度优先搜索/PushBoxGame/PushBoxGame/main.cpp -------------------------------------------------------------------------------- /图论/广度优先搜索/PushBoxGame/PushBoxGame/path.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/广度优先搜索/PushBoxGame/PushBoxGame/path.cpp -------------------------------------------------------------------------------- /图论/广度优先搜索/PushBoxGame/PushBoxGame/path.h: -------------------------------------------------------------------------------- 1 | #include "commondef.h" 2 | 3 | class Path { 4 | public: 5 | Path(); 6 | virtual ~Path(); 7 | 8 | private: 9 | int *pathchain_; 10 | 11 | public: 12 | void finalize(); 13 | void initialize(); 14 | void add(int nowpath, int prepath); 15 | void getPath(int start, vector & path); 16 | }; 17 | -------------------------------------------------------------------------------- /图论/广度优先搜索/PushBoxGame/PushBoxGame/pushboxgame.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/广度优先搜索/PushBoxGame/PushBoxGame/pushboxgame.cpp -------------------------------------------------------------------------------- /图论/广度优先搜索/PushBoxGame/PushBoxGame/pushboxgame.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/广度优先搜索/PushBoxGame/PushBoxGame/pushboxgame.h -------------------------------------------------------------------------------- /图论/广度优先搜索/PushBoxGame/PushBoxGame/pushboxstate.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/广度优先搜索/PushBoxGame/PushBoxGame/pushboxstate.cpp -------------------------------------------------------------------------------- /图论/广度优先搜索/PushBoxGame/PushBoxGame/pushboxstate.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/广度优先搜索/PushBoxGame/PushBoxGame/pushboxstate.h -------------------------------------------------------------------------------- /图论/广度优先搜索/最短路BFS样例.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | #define MAXN 20 7 | #define inf -1 8 | 9 | int adj[MAXN][MAXN]; 10 | int n; 11 | int dis[MAXN]; 12 | 13 | void bfs(int u) { 14 | queue q; 15 | memset(dis, inf, sizeof(dis)); 16 | 17 | dis[u] = 0; 18 | q.push(u); 19 | 20 | while(!q.empty()) { 21 | u = q.front(); 22 | q.pop(); 23 | 24 | for(int v = 1; v <= n; ++v) { 25 | if(!adj[u][v]) continue; 26 | if(dis[v] != inf) continue; 27 | 28 | dis[v] = dis[u] + 1; 29 | q.push(v); 30 | } 31 | } 32 | } 33 | 34 | void bfs_printf() { 35 | for(int i = 1; i <= n; ++i) { 36 | printf("dis[%d] = %d\n", i, dis[i]); 37 | } 38 | 39 | } 40 | 41 | int main() { 42 | int m; 43 | while(scanf("%d %d", &n, &m) != EOF) { 44 | memset(adj, 0, sizeof(adj)); 45 | while(m--) { 46 | int u, v; 47 | scanf("%d %d", &u, &v); 48 | adj[u][v] = adj[v][u] = 1; 49 | } 50 | bfs(1); 51 | bfs_printf(); 52 | } 53 | return 0; 54 | } 55 | 56 | /* 57 | 58 | 10 11 59 | 2 1 60 | 1 3 61 | 1 4 62 | 1 5 63 | 7 1 64 | 10 2 65 | 10 8 66 | 8 7 67 | 7 9 68 | 4 5 69 | 5 6 70 | 71 | */ 72 | -------------------------------------------------------------------------------- /图论/广度优先搜索/迷宫搜索 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/广度优先搜索/迷宫搜索 模板.cpp -------------------------------------------------------------------------------- /图论/广度优先搜索/迷宫救公主.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/广度优先搜索/迷宫救公主.cpp -------------------------------------------------------------------------------- /图论/强连通分量/2_sat 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/强连通分量/2_sat 模板.cpp -------------------------------------------------------------------------------- /图论/最短路/BellmanFord 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/最短路/BellmanFord 模板.cpp -------------------------------------------------------------------------------- /图论/最短路/Dijkstra + Heap 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/最短路/Dijkstra + Heap 模板.cpp -------------------------------------------------------------------------------- /图论/最短路/Dijkstra 模板.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | typedef int ValueType; 8 | const int maxn = 1010; 9 | const int maxm = 2000010; 10 | const int INVALID_INDEX = -1; 11 | const ValueType inf = 1e9; 12 | 13 | struct Edge { 14 | int u, v, next; 15 | ValueType w; 16 | Edge(){} 17 | Edge(int _u, int _v, ValueType _w, int _next) : 18 | u(_u), v(_v), w(_w), next(_next) 19 | { 20 | } 21 | }edges[maxm]; 22 | 23 | int head[maxn], edgeCount; 24 | ValueType dist[maxn]; 25 | bool visited[maxn]; 26 | 27 | void init() { 28 | edgeCount = 0; 29 | memset(head, -1, sizeof(head)); 30 | } 31 | 32 | void addEdge(int u, int v, ValueType w) { 33 | edges[edgeCount] = Edge(u, v, w, head[u]); 34 | head[u] = edgeCount++; 35 | } 36 | 37 | void Dijkstra_Init(int n, int st, ValueType *dist) { 38 | for (int i = 0; i < n; ++i) { 39 | dist[i] = (st == i) ? 0 : inf; 40 | visited[i] = false; 41 | } 42 | } 43 | 44 | int Dijkstra_FindMin(int n, ValueType *dist) { 45 | int u = INVALID_INDEX; 46 | for (int i = 0; i < n; ++i) { 47 | if (visited[i]) 48 | continue; 49 | if (u == INVALID_INDEX || dist[i] < dist[u]) { 50 | u = i; 51 | } 52 | } 53 | return u; 54 | } 55 | 56 | void Dijkstra_Update(int u, ValueType *dist) { 57 | visited[u] = true; 58 | for (int e = head[u]; ~e; e = edges[e].next) { 59 | int v = edges[e].v; 60 | int w = edges[e].w; 61 | dist[v] = min( dist[v], (dist[u] + w) ); 62 | } 63 | } 64 | 65 | void Dijkstra(int n, int st, ValueType *dist) { 66 | Dijkstra_Init(n, st, dist); 67 | while (true) { 68 | int u = Dijkstra_FindMin(n, dist); 69 | if (u == INVALID_INDEX) break; 70 | Dijkstra_Update(u, dist); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /图论/最短路/FloydWarshall 模板.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | 8 | typedef int ValueType; 9 | const int maxn = 105; 10 | const ValueType inf = 1e9; 11 | ValueType mat[maxn][maxn]; 12 | 13 | void init(int n) { 14 | for (int i = 0; i < n; ++i) { 15 | for (int j = 0; j < n; ++j) { 16 | mat[i][j] = (i == j) ? 0 : inf; 17 | } 18 | } 19 | } 20 | 21 | void addEdge(int u, int v, ValueType w) { 22 | mat[u][v] = min(mat[u][v], w); 23 | } 24 | 25 | void FloydWarshall(int n) { 26 | int i, j, k; 27 | for (k = 0; k < n; ++k) 28 | for (i = 0; i < n; ++i) 29 | for (j = 0; j < n; ++j) 30 | mat[i][j] = min(mat[i][j], mat[i][k] + mat[k][j]); 31 | } -------------------------------------------------------------------------------- /图论/最短路/SPFA 模板.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | typedef long long ValueType; 10 | const int maxn = 1000010; 11 | const int maxm = 1000010; 12 | const ValueType inf = (ValueType)1e9 * 1e9; 13 | 14 | struct Edge { 15 | int u, v, next; 16 | ValueType w; 17 | Edge(){} 18 | Edge(int _u, int _v, ValueType _w, int _next) : 19 | u(_u), v(_v), w(_w), next(_next) 20 | { 21 | } 22 | }edges[maxm]; 23 | 24 | int head[maxn], edgeCount; 25 | int visited[maxn]; 26 | bool inqueue[maxn]; 27 | 28 | void init() { 29 | edgeCount = 0; 30 | memset(head, -1, sizeof(head)); 31 | } 32 | 33 | void addEdge(int u, int v, ValueType w) { 34 | edges[edgeCount] = Edge(u, v, w, head[u]); 35 | head[u] = edgeCount++; 36 | } 37 | 38 | void SPFAInit(int n, int st, queue & que, ValueType *dist) { 39 | for (int i = 0; i < n; ++i) { 40 | dist[i] = (st == i) ? 0 : inf; 41 | inqueue[i] = (st == i); 42 | visited[i] = 0; 43 | } 44 | que.push(st); 45 | } 46 | 47 | void SPFAUpdate(int u, queue & que, ValueType *dist) { 48 | for (int e = head[u]; ~e; e = edges[e].next) { 49 | int v = edges[e].v; 50 | if (dist[u] + edges[e].w < dist[v]) { 51 | dist[v] = dist[u] + edges[e].w; 52 | if (!inqueue[v]) { 53 | inqueue[v] = true; 54 | que.push(v); 55 | } 56 | } 57 | } 58 | } 59 | 60 | void SPFA(int n, int st, ValueType *dist) { 61 | queue que; 62 | SPFAInit(n, st, que, dist); 63 | while (!que.empty()) { 64 | int u = que.front(); 65 | que.pop(); 66 | inqueue[u] = false; 67 | if (visited[u] ++ > n) { 68 | break; 69 | } 70 | SPFAUpdate(u, que, dist); 71 | } 72 | } 73 | 74 | 75 | -------------------------------------------------------------------------------- /图论/最近公共祖先 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/最近公共祖先 模板.cpp -------------------------------------------------------------------------------- /图论/深度优先搜索/全排列DFS样例.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | #define MAXN 4 7 | 8 | bool visit[MAXN + 1]; 9 | int ans[MAXN], ansSize; 10 | 11 | void dfs_init() { 12 | memset(visit, 0, sizeof(visit)); 13 | ansSize = 0; 14 | } 15 | 16 | void dfs_add(int u) { 17 | visit[u] = true; 18 | ans[ansSize] = u; 19 | ++ansSize; 20 | } 21 | 22 | void dfs_dec(int u) { 23 | --ansSize; 24 | visit[u] = false; 25 | } 26 | 27 | void dfs_print() { 28 | for(int i = 0; i < ansSize; ++i) { 29 | printf("%d ", ans[i]); 30 | } 31 | puts(""); 32 | } 33 | 34 | void dfs(int depth) { 35 | if(depth == MAXN) { 36 | dfs_print(); 37 | return; 38 | } 39 | for(int i = 1; i <= MAXN; ++i) { 40 | int v = i; 41 | if(!visit[v]) { 42 | dfs_add(v); 43 | dfs(depth+1); 44 | dfs_dec(v); 45 | } 46 | 47 | } 48 | } 49 | 50 | int main() { 51 | dfs_init(); 52 | dfs(0); 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /图论/深度优先搜索/斐波那契数列DFS样例.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | 6 | int dfs(unsigned int n) { 7 | if(n <= 1) { 8 | return 1; 9 | } 10 | return dfs(n-1) + dfs(n-2); 11 | } 12 | 13 | int main() { 14 | int n; 15 | while(scanf("%d", &n) != EOF) { 16 | printf("%d\n", dfs(n)); 17 | } 18 | return 0; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /图论/深度优先搜索/简易DFS样例.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | const int MAXN = 7; 7 | 8 | bool visit[MAXN]; 9 | int ans[MAXN], ansSize; 10 | 11 | bool adj[MAXN][MAXN] = { 12 | {0, 1, 1, 0, 0, 0, 0}, 13 | {1, 0, 0, 1, 1, 0, 0}, 14 | {1, 0, 0, 0, 0, 1, 1}, 15 | {0, 1, 0, 0, 0, 0, 0}, 16 | {0, 1, 0, 0, 0, 1, 0}, 17 | {0, 0, 1, 0, 1, 0, 0}, 18 | {0, 0, 1, 0, 0, 0, 0}, 19 | }; 20 | 21 | void dfs_init() { 22 | memset(visit, 0, sizeof(visit)); 23 | ansSize = 0; 24 | } 25 | 26 | void dfs_add(int u) { 27 | ans[ansSize++] = u; 28 | } 29 | 30 | void dfs_print() { 31 | for(int i = 0; i < ansSize; ++i) { 32 | printf("%d ", ans[i]); 33 | } 34 | puts(""); 35 | } 36 | 37 | void dfs(int u) { 38 | if(visit[u]) { 39 | return ; 40 | } 41 | visit[u] = true; 42 | dfs_add(u); 43 | for(int i = 0; i < MAXN; ++i) { 44 | int v = i; 45 | if(adj[u][v]) { 46 | dfs(v); 47 | } 48 | } 49 | } 50 | 51 | int main() { 52 | dfs_init(); 53 | dfs(0); 54 | dfs_print(); 55 | return 0; 56 | } 57 | 58 | 59 | -------------------------------------------------------------------------------- /图论/深度优先搜索/记忆化搜索求最大值样例.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | const int MAXN = 6; 7 | int D[MAXN][MAXN]; 8 | 9 | int gold[MAXN][MAXN] = { 10 | {0, 0, 0, 1, 0, 0}, 11 | {0, 0, 2, 0, 5, 0}, 12 | {0, 3, 0, 5, 0, 0}, 13 | {1, 0, 2, 0, 0, 0}, 14 | }; 15 | 16 | void dfs_init() { 17 | memset(D, -1, sizeof(D)); 18 | } 19 | 20 | 21 | 22 | void dfs_print() { 23 | for(int i = 0; i < 4; ++i) { 24 | for(int j = 0; j < 6; ++j) { 25 | printf("%d ", D[i][j]); 26 | } 27 | puts(""); 28 | } 29 | } 30 | 31 | int dfs(int i, int j) { 32 | if(i == 0 && j == 0) { 33 | return D[0][0] = gold[0][0]; 34 | } 35 | if(i < 0 || j < 0) { 36 | return 0; 37 | } 38 | if(D[i][j] != -1) { 39 | return D[i][j]; 40 | } 41 | return D[i][j] = gold[i][j] + max(dfs(i-1,j), dfs(i, j-1)); 42 | } 43 | 44 | int main() { 45 | dfs_init(); 46 | dfs(3, 5); 47 | dfs_print(); 48 | return 0; 49 | } 50 | 51 | 52 | -------------------------------------------------------------------------------- /图论/深度优先搜索/阶乘求解DFS样例.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int dfs(int n) { 6 | return !n ? 1 : n * dfs(n-1); 7 | } 8 | 9 | int main() { 10 | int n; 11 | while(scanf("%d", &n) != EOF) { 12 | printf("%d\n", dfs(n)); 13 | } 14 | return 0; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /图论/稳定婚姻 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/图论/稳定婚姻 模板.cpp -------------------------------------------------------------------------------- /大数/KaraTsuba 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/大数/KaraTsuba 模板.cpp -------------------------------------------------------------------------------- /大数/大数 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/大数/大数 模板.cpp -------------------------------------------------------------------------------- /大数/高精分数 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/大数/高精分数 模板.cpp -------------------------------------------------------------------------------- /字符串/Manacher 模板.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Manacher算法(求解字符串最长回文) 3 | 1.将字符串间隔插入一个全新字符,将字符串转换成奇数长度; 4 | 2.线性枚举每个字符为中心轴,计算第i个字符的最长回文半径p[i]; 5 | a.利用之前的计算结果获得p[i]初始值; 6 | b.两边扩展,更新p[i]值; 7 | c.利用i+p[i]更新核心中心轴; 8 | d.利用2*p[i]-1更新最长回文长度 9 | Author: WhereIsHeroFrom 10 | Update Time: 2018-3-24 11 | Algorithm Complexity: O(n) 12 | */ 13 | 14 | #include 15 | #include 16 | 17 | using namespace std; 18 | 19 | #define MAXN 1000010 20 | int p[MAXN]; 21 | char strTmp[MAXN]; 22 | 23 | int Min(int a, int b) { 24 | return a < b ? a : b; 25 | } 26 | 27 | void ManacherPre(char *str) { 28 | strcpy(strTmp, str); 29 | int i; 30 | for(i = 0; strTmp[i]; ++i) { 31 | str[2*i] = '$'; 32 | str[2*i+1] = strTmp[i]; 33 | } 34 | str[2*i] = '$'; 35 | str[2*i+1] = '\0'; 36 | } 37 | 38 | int Manacher(char *str) { 39 | int ct = 0, r = 0, maxLen = 1; 40 | p[0] = 1; 41 | for(int i = 1; str[i]; ++i) { 42 | // 1.计算p[i]初始值 43 | if(i < r) { 44 | p[i] = Min(p[2*ct-i], r-i); 45 | }else { 46 | p[i] = 1; 47 | } 48 | // 2.扩张p[i],以适应达到p[i]最大值 49 | while(i-p[i]>=0 && str[i-p[i]] == str[i+p[i]]) 50 | ++p[i]; 51 | 52 | // 3.更新ct 53 | if(p[i] + i > r) { 54 | ct = i; 55 | r = p[i] + i; 56 | } 57 | // 4.更新最长回文 58 | if(2*p[i]-1 > maxLen) { 59 | maxLen = 2*p[i] - 1; 60 | } 61 | } 62 | return maxLen; 63 | } 64 | 65 | 66 | 67 | char str[MAXN]; 68 | 69 | int main() { 70 | while(scanf("%s", str) != EOF) { 71 | ManacherPre(str); 72 | int len = Manacher(str); 73 | printf("%d\n", len/2); 74 | } 75 | return 0; 76 | } 77 | -------------------------------------------------------------------------------- /字符串/kmp.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | #pragma warning(disable:4996) 6 | 7 | #define NULL_MATCH (-1) 8 | #define Type char 9 | #define MAXN 1000010 10 | 11 | /* 12 | "ababaaba" 13 | 14 | */ 15 | void GenNext(int *next, Type* M, int MLen) { 16 | // 0. 用 NULL_MATCH(-1) 代表一定没有真前缀,0的位置一定没有真前缀,所以为 NULL_MATCH 17 | int MPos = NULL_MATCH; 18 | next[0] = MPos; 19 | for (int TPos = 1; TPos < MLen; ++TPos) { 20 | // 1. M[TPos-MPos-1...TPos-1] 和 M[0...MPos] 完全匹配 21 | // 检测 M[TPos] 和 M[MPos + 1] 是否匹配,不匹配,则找下一个 MPos' = next[MPos]; 22 | while (MPos != NULL_MATCH && M[TPos] != M[MPos + 1]) 23 | MPos = next[MPos]; 24 | // 2. 正确匹配上,自增 MPos 25 | if (M[TPos] == M[MPos + 1]) MPos++; 26 | // 3. M[TPos-MPos...TPos] 和 M[0...MPos] 完全匹配 27 | next[TPos] = MPos; 28 | } 29 | /*for (int i = 0; i < MLen; ++i) { 30 | printf("|%d", i); 31 | } 32 | puts(""); 33 | 34 | for (int i = 0; i < MLen; ++i) { 35 | printf("|%c", M[i]); 36 | } 37 | puts(""); 38 | 39 | for (int i = 0; i < MLen; ++i) { 40 | printf("|-"); 41 | } 42 | puts(""); 43 | 44 | 45 | 46 | for (int i = 0; i < MLen; ++i) { 47 | printf("%d --> %d\n", i, next[i]); 48 | } 49 | puts("");*/ 50 | 51 | /*for (int i = 0; i < MLen; ++i) { 52 | printf("|%d", next[i]); 53 | } 54 | puts("");*/ 55 | 56 | } 57 | 58 | int KMP(int *next, Type* M, int MLen, Type *T, int TLen) { 59 | // 1. 这里设置成 -1 的目的是: 60 | // 最初认为的情况是 目标串的空串 和 匹配串的空串 一定匹配 61 | int MPos = NULL_MATCH; 62 | for (int TPos = 0; TPos < TLen; ++TPos) { 63 | // 2. 前提是 T[...TPos-1] == M[0...MPos] (MPos == -1 则代表两个空串匹配,同样成立) 64 | // 如果 T[TPos] != M[MPos + 1],则 MPos = MPos' 继续匹配 65 | while (MPos != NULL_MATCH && T[TPos] != M[MPos + 1]) 66 | MPos = next[MPos]; 67 | // 3. 当 T[TPos] == M[MPos + 1] 则 TPos++, MPos++; 68 | if (T[TPos] == M[MPos + 1]) MPos++; 69 | // 4. 匹配完毕,返回 目标串 第一个匹配的位置 70 | if (MPos == MLen - 1) { 71 | // ... 72 | } 73 | } 74 | return MPos; 75 | } 76 | 77 | 78 | 79 | int Next[MAXN]; 80 | Type T[MAXN], TT[MAXN], M[MAXN]; 81 | -------------------------------------------------------------------------------- /字符串/字典树/字典树 01模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/字符串/字典树/字典树 01模板.cpp -------------------------------------------------------------------------------- /字符串/字典树/字典树 力扣简易版.cpp: -------------------------------------------------------------------------------- 1 | class TrieNode { 2 | public: 3 | bool end; // 1 表示从根结点到它是一个完整字典中的串 4 | // 0 表示它是某个字符串的前缀 5 | TrieNode *next[26]; // 指向所有的子结点 6 | 7 | TrieNode() { 8 | end = false; 9 | memset(next, 0, sizeof(next)); 10 | } 11 | }; 12 | 13 | class Trie { 14 | TrieNode* root; 15 | public: 16 | Trie() { 17 | root = new TrieNode(); 18 | } 19 | 20 | void insert(string word) { 21 | TrieNode *now = root; 22 | for(int i = 0; i < word.size(); ++i) { 23 | int child = word[i] - 'a'; 24 | if( nullptr == now->next[child] ) { 25 | now->next[child] = new TrieNode(); 26 | } 27 | now = now->next[child]; 28 | } 29 | now->end = true; 30 | } 31 | 32 | bool search(string word) { 33 | TrieNode *now = root; 34 | for(int i = 0; i < word.size(); ++i) { 35 | int child = word[i] - 'a'; 36 | if( nullptr == now->next[child]) { 37 | return false; 38 | } 39 | now = now->next[child]; 40 | } 41 | return now->end; 42 | } 43 | 44 | bool startsWith(string prefix) { 45 | TrieNode *now = root; 46 | for(int i = 0; i < prefix.size(); ++i) { 47 | int child = prefix[i] - 'a'; 48 | if( nullptr == now->next[child]) { 49 | return false; 50 | } 51 | now = now->next[child]; 52 | } 53 | return true; 54 | } 55 | }; 56 | -------------------------------------------------------------------------------- /字符串/字典树/字典树 字母模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/字符串/字典树/字典树 字母模板.cpp -------------------------------------------------------------------------------- /字符串/朴素回文串.c: -------------------------------------------------------------------------------- 1 | #define maxn 1010 2 | bool isPal[1010][1010]; 3 | 4 | void preCalc(char *s) { 5 | int i, j; 6 | int l, r; 7 | int len = strlen(s); 8 | for(i = 0; i < len; ++i) { 9 | // 奇数 10 | for(j = 0; j < len; ++j) { 11 | l = i-j; 12 | r = i+j; 13 | if(l < 0 || r >= len) { 14 | break; 15 | } 16 | if(l == r) { 17 | isPal[l][r] = true; 18 | }else 19 | isPal[l][r] = ( (s[l] == s[r]) && isPal[l+1][r-1] ); 20 | } 21 | // 偶数 22 | for(j = 0; j < len; ++j) { 23 | l = i-j; 24 | r = i+1+j; 25 | if(l < 0 || r >= len) { 26 | break; 27 | } 28 | if(l + 1 == r) { 29 | isPal[l][r] = (s[l] == s[r]); 30 | }else 31 | isPal[l][r] = (s[l] == s[r]) && isPal[l+1][r-1]; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /数据结构/画解数据结构/二叉树/二叉搜索树 BST/二叉搜索树.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数据结构/画解数据结构/二叉树/二叉搜索树 BST/二叉搜索树.c -------------------------------------------------------------------------------- /数据结构/画解数据结构/二叉树/平衡二叉树 AVL/AVL 树.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数据结构/画解数据结构/二叉树/平衡二叉树 AVL/AVL 树.c -------------------------------------------------------------------------------- /数据结构/画解数据结构/双端队列/双端队列链表实现.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数据结构/画解数据结构/双端队列/双端队列链表实现.c -------------------------------------------------------------------------------- /数据结构/画解数据结构/双端队列/双端队列顺序表实现.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数据结构/画解数据结构/双端队列/双端队列顺序表实现.c -------------------------------------------------------------------------------- /数据结构/画解数据结构/哈希表/散列哈希 - 开方定址法.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数据结构/画解数据结构/哈希表/散列哈希 - 开方定址法.c -------------------------------------------------------------------------------- /数据结构/画解数据结构/哈希表/散列哈希 - 直接定址法.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数据结构/画解数据结构/哈希表/散列哈希 - 直接定址法.c -------------------------------------------------------------------------------- /数据结构/画解数据结构/图/最小生成树/boruvka.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数据结构/画解数据结构/图/最小生成树/boruvka.cpp -------------------------------------------------------------------------------- /数据结构/画解数据结构/图/最小生成树/kruscal.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数据结构/画解数据结构/图/最小生成树/kruscal.cpp -------------------------------------------------------------------------------- /数据结构/画解数据结构/图/最小生成树/prim.cpp: -------------------------------------------------------------------------------- 1 | int minSpanningTree(int n, int dist[maxn][maxn]) { 2 | int i, u, ret, dis; 3 | int cost[maxn]; 4 | for(i = 0; i < n; ++i) { 5 | cost[i] = (i == 0) ? 0 : dist[0][i]; // (1) 6 | } 7 | ret = 0; // (2) 8 | while(1) { 9 | dis = inf; 10 | for(i = 0; i < n; ++i) { // (3) 11 | if(cost[i] && lessthan(cost[i], dis) ) { 12 | dis = cost[i]; 13 | u = i; 14 | } 15 | } 16 | if(dis == inf) { 17 | return ret; // (4) 18 | } 19 | ret += cost[u]; // (5) 20 | cost[u] = 0; // (6) 21 | for(i = 0; i < n; ++i) { // (7) 22 | if(cost[i] && lessthan(dist[u][i], cost[i])) { 23 | cost[i] = dist[u][i]; 24 | } 25 | } 26 | } 27 | 28 | return inf; 29 | } 30 | -------------------------------------------------------------------------------- /数据结构/画解数据结构/堆/堆.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数据结构/画解数据结构/堆/堆.c -------------------------------------------------------------------------------- /数据结构/画解数据结构/思维导图地址.txt: -------------------------------------------------------------------------------- 1 | 《画解数据结构》思维导图:https://docs.qq.com/desktop/mydoc/folder/SYdfgwjieWce 2 | 《画解数据结构》文章目录:https://blog.csdn.net/WhereIsHeroFrom/article/details/119709503 3 | -------------------------------------------------------------------------------- /数据结构/画解数据结构/排序/冒泡排序.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int a[1010]; 4 | 5 | void Input(int n, int *a) { 6 | for(int i = 0; i < n; ++i) { 7 | scanf("%d", &a[i]); 8 | } 9 | } 10 | 11 | void Output(int n, int *a) { 12 | for(int i = 0; i < n; ++i) { 13 | if(i) 14 | printf(" "); 15 | printf("%d", a[i]); 16 | } 17 | puts(""); 18 | } 19 | 20 | void Swap(int *a, int *b) { 21 | int tmp = *a; 22 | *a = *b; 23 | *b = tmp; 24 | } 25 | 26 | void BubbleSort(int n, int *a) { // (1) 27 | bool swapped; 28 | int last = n; 29 | do { 30 | swapped = false; // (2) 31 | for(int i = 0; i < last - 1; ++i) { // (3) 32 | if(a[i] > a[i+1]) { // (4) 33 | Swap(&a[i], &a[i+1]); // (5) 34 | swapped = true; // (6) 35 | } 36 | } 37 | --last; 38 | }while (swapped); 39 | } 40 | 41 | int main() { 42 | int n; 43 | while(scanf("%d", &n) != EOF) { 44 | Input(n, a); 45 | BubbleSort(n, a); 46 | Output(n, a); 47 | } 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /数据结构/画解数据结构/排序/基数排序.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数据结构/画解数据结构/排序/基数排序.cpp -------------------------------------------------------------------------------- /数据结构/画解数据结构/排序/希尔排序.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数据结构/画解数据结构/排序/希尔排序.cpp -------------------------------------------------------------------------------- /数据结构/画解数据结构/排序/归并排序.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数据结构/画解数据结构/排序/归并排序.cpp -------------------------------------------------------------------------------- /数据结构/画解数据结构/排序/快速排序 - 实现1.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数据结构/画解数据结构/排序/快速排序 - 实现1.cpp -------------------------------------------------------------------------------- /数据结构/画解数据结构/排序/快速排序 - 实现2.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数据结构/画解数据结构/排序/快速排序 - 实现2.cpp -------------------------------------------------------------------------------- /数据结构/画解数据结构/排序/插入排序.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int a[1010]; 4 | 5 | void input(int n, int *a) { 6 | for(int i = 0; i < n; ++i) { 7 | scanf("%d", &a[i]); 8 | } 9 | } 10 | 11 | void output(int n, int *a) { 12 | for(int i = 0; i < n; ++i) { 13 | if(i) 14 | printf(" "); 15 | printf("%d", a[i]); 16 | } 17 | puts(""); 18 | } 19 | 20 | void swap(int *a, int *b) { 21 | int tmp = *a; 22 | *a = *b; 23 | *b = tmp; 24 | } 25 | 26 | void InsertSort(int n, int *a) { // (1) 27 | int i, j; 28 | for(i = 1; i < n; ++i) { 29 | int x = a[i]; // (2) 30 | for(j = i-1; j >= 0; --j) { // (3) 31 | if(a[j] >= x) { // (4) 32 | a[j+1] = a[j]; // (5) 33 | }else 34 | break; // (6) 35 | } 36 | a[j+1] = x; // (7) 37 | } 38 | } 39 | 40 | int main() { 41 | int n; 42 | while(scanf("%d", &n) != EOF) { 43 | input(n, a); 44 | InsertSort(n, a); 45 | output(n, a); 46 | } 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /数据结构/画解数据结构/排序/计数排序.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数据结构/画解数据结构/排序/计数排序.cpp -------------------------------------------------------------------------------- /数据结构/画解数据结构/排序/选择排序.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | int a[1010]; 5 | 6 | void input(int n, int *a) { 7 | for(int i = 0; i < n; ++i) { 8 | scanf("%d", &a[i]); 9 | } 10 | } 11 | 12 | void output(int n, int *a) { 13 | for(int i = 0; i < n; ++i) { 14 | if(i) 15 | printf(" "); 16 | printf("%d", a[i]); 17 | } 18 | puts(""); 19 | } 20 | 21 | void swap(int *a, int *b) { 22 | int tmp = *a; 23 | *a = *b; 24 | *b = tmp; 25 | } 26 | 27 | void SelectionSort(int n, int *a) { // (1) 28 | int i, j; 29 | for(i = 0; i < n - 1; ++i) { // (2) 30 | int min = i; // (3) 31 | for(j = i+1; j < n; ++j) { // (4) 32 | if(a[j] < a[min]) { 33 | min = j; // (5) 34 | } 35 | } 36 | swap(&a[i], &a[min]); // (6) 37 | } 38 | } 39 | 40 | int main() { 41 | int n; 42 | while(scanf("%d", &n) != EOF) { 43 | input(n, a); 44 | SelectionSort(n, a); 45 | output(n, a); 46 | } 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /数据结构/画解数据结构/栈/线性表实现栈.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数据结构/画解数据结构/栈/线性表实现栈.c -------------------------------------------------------------------------------- /数据结构/画解数据结构/栈/链表实现栈.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数据结构/画解数据结构/栈/链表实现栈.c -------------------------------------------------------------------------------- /数据结构/画解数据结构/树/二叉树链表存储.c: -------------------------------------------------------------------------------- 1 | #define MAXN 1024 2 | #define DataType int 3 | 4 | 5 | typedef struct TreeNode { 6 | DataType data; 7 | struct TreeNode *left; 8 | struct TreeNode *right; 9 | }TreeNode; 10 | 11 | typedef struct { 12 | TreeNode nodes[MAXN]; 13 | int root; 14 | int n; 15 | }Tree; 16 | -------------------------------------------------------------------------------- /数据结构/画解数据结构/树/孩子表示法.c: -------------------------------------------------------------------------------- 1 | #define MAXN 1024 2 | #define DataType int 3 | 4 | typedef struct { 5 | DataType data; 6 | int childCount; 7 | int childs[MAXN]; 8 | }TreeNode; 9 | 10 | typedef struct { 11 | TreeNode nodes[MAXN]; 12 | int root; 13 | int n; 14 | }Tree; 15 | -------------------------------------------------------------------------------- /数据结构/画解数据结构/树/左儿子右兄弟表示法.c: -------------------------------------------------------------------------------- 1 | #define MAXN 1024 2 | #define DataType int 3 | 4 | typedef struct { 5 | DataType data; 6 | int left; 7 | int right; 8 | }TreeNode; 9 | 10 | typedef struct { 11 | TreeNode nodes[MAXN]; 12 | int root; 13 | int n; 14 | }Tree; 15 | -------------------------------------------------------------------------------- /数据结构/画解数据结构/树/父亲表示法.c: -------------------------------------------------------------------------------- 1 | #define MAXN 1024 2 | #define DataType int 3 | 4 | typedef struct { 5 | DataType data; 6 | int parent; 7 | }TreeNode; 8 | 9 | typedef struct { 10 | TreeNode nodes[MAXN]; 11 | int root; 12 | int n; 13 | }Tree; 14 | 15 | -------------------------------------------------------------------------------- /数据结构/画解数据结构/树/遍历.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数据结构/画解数据结构/树/遍历.c -------------------------------------------------------------------------------- /数据结构/画解数据结构/链表/单向链表.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数据结构/画解数据结构/链表/单向链表.cpp -------------------------------------------------------------------------------- /数据结构/画解数据结构/队列/链表实现队列.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数据结构/画解数据结构/队列/链表实现队列.c -------------------------------------------------------------------------------- /数据结构/画解数据结构/队列/顺序表实现队列.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数据结构/画解数据结构/队列/顺序表实现队列.c -------------------------------------------------------------------------------- /数据结构/画解数据结构/顺序表(数组)/数组的基本操作.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数据结构/画解数据结构/顺序表(数组)/数组的基本操作.c -------------------------------------------------------------------------------- /数据结构/高级数据结构/单调栈/单调栈 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数据结构/高级数据结构/单调栈/单调栈 模板.cpp -------------------------------------------------------------------------------- /数据结构/高级数据结构/单调栈/直方图的最大子矩形.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数据结构/高级数据结构/单调栈/直方图的最大子矩形.cpp -------------------------------------------------------------------------------- /数据结构/高级数据结构/单调队列/单调队列.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数据结构/高级数据结构/单调队列/单调队列.c -------------------------------------------------------------------------------- /数论/Eratosthenes筛选 模板.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Eratosthenes素数筛选 3 | 利用素数的倍数必然是合数这个性质,从小到大枚举,标记所有合数。 4 | Author: WhereIsHeroFrom 5 | Update Time: 2018-3-19 6 | Algorithm Complexity: O(n) 7 | */ 8 | 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | const int MAXP = 65536; 14 | #define ll long long 15 | 16 | int primes[MAXP]; 17 | bool notprime[MAXP]; 18 | 19 | void Eratosthenes() { 20 | memset(notprime, false, sizeof(notprime)); 21 | notprime[1] = true; 22 | primes[0] = 0; 23 | for(int i = 2; i < MAXP; i++) { 24 | if( !notprime[i] ) { 25 | primes[ ++primes[0] ] = i; 26 | //需要注意i*i超出整型后变成负数的问题,所以转化成 __int64 27 | for(ll j = (ll)i*i; j < MAXP; j += i) { 28 | notprime[j] = true; 29 | } 30 | } 31 | } 32 | } 33 | 34 | int main() { 35 | Eratosthenes(); 36 | printf("%d\n", primes[0]); 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /数论/Lucas定理 模板.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Lucas定理 3 | 4 | 组合数c(n,m) mod p 5 | Lucas(n, m, p) = Lucas(n/p, m/p, p) * C(n%p, m%p, p) % p 6 | 7 | n 20 | #include 21 | 22 | #define ll long long 23 | #define maxn 100010 24 | 25 | ll FacCache[maxn]; 26 | 27 | // 二分快速幂 28 | ll Exp(ll a, ll n, ll Mod){ 29 | ll ans = 1; 30 | while (n){ 31 | if (n & 1) ans = ans * a % Mod; 32 | a = a * a % Mod; 33 | n >>= 1; 34 | } 35 | return ans; 36 | } 37 | 38 | // 费马小定理 39 | ll Inv(ll a, ll p) { 40 | return Exp(a, p-2, p); 41 | } 42 | 43 | // 计算阶乘 模 p,存入 FacCache 44 | void CalcCache(int n, int p) { 45 | FacCache[0] = 1 % p; 46 | for(int i = 1; i <= n; ++i) { 47 | FacCache[i] = FacCache[i-1] * i; 48 | if(FacCache[i] >= p) FacCache[i] %= p; 49 | } 50 | } 51 | 52 | // 小组合数模 p 53 | // n,m < p 54 | ll SmallComb(int n, int m, int p) { 55 | if(m == 0 || m == n) { 56 | return 1; 57 | }else if(m > n) { 58 | return 0; 59 | } 60 | // n! * m!^(-1) * (n-m)!^(-1) 61 | ll ans = FacCache[n] * Inv( FacCache[m], p) % p; 62 | return ans * Inv( FacCache[n-m], p) % p; 63 | } 64 | 65 | // lucas 定理 66 | ll Lucas (ll n, ll m, int p) { 67 | if(m == 0) { 68 | return 1; 69 | } 70 | return Lucas(n/p, m/p, p) * SmallComb(n % p, m % p, p) % p; 71 | } 72 | 73 | // 大组合数模 p 74 | ll BigComb(ll n, ll m, int p) { 75 | if(p == 1) { 76 | return 0; 77 | } 78 | CalcCache(p, p); 79 | return Lucas(n, m, p); 80 | } 81 | 82 | 83 | -------------------------------------------------------------------------------- /数论/中国剩余定理/中国剩余定理 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数论/中国剩余定理/中国剩余定理 模板.cpp -------------------------------------------------------------------------------- /数论/中国剩余定理/朴素枚举 模板.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | const int MAXN = 3; 6 | int m[MAXN] = {4, 6, 15}; 7 | int a[MAXN] = {2, 4, 7}; 8 | 9 | int main() { 10 | for(int x = 0; x < 400; ++x) { 11 | bool bfind = true; 12 | for(int i = 0; i < MAXN; ++i) { 13 | if( x % m[i] != a[i] ) { 14 | bfind = false; 15 | break; 16 | } 17 | } 18 | if(bfind) { 19 | printf("%d\n", x); 20 | } 21 | } 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /数论/二分快速幂.cpp: -------------------------------------------------------------------------------- 1 | #define ll long long 2 | 3 | ll Exp(ll a, ll n, ll Mod){ 4 | ll ans = 1; 5 | while (n){ 6 | if (n & 1) ans = ans * a % Mod; 7 | a = a * a % Mod; 8 | n >>= 1; 9 | } 10 | return ans; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /数论/因子加减法 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数论/因子加减法 模板.cpp -------------------------------------------------------------------------------- /数论/因子筛选.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数论/因子筛选.cpp -------------------------------------------------------------------------------- /数论/因式分解.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 因式分解 3 | 素数筛选后,试除sqrt(n)以内的所有素数,层层约去。 4 | 5 | Author: WhereIsHeroFrom 6 | Update Time: 2018-3-21 7 | Algorithm Complexity: O(sqrt(n)) 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | using namespace std; 14 | 15 | const int maxn = 100005; 16 | #define ll long long 17 | 18 | int primes[maxn]; 19 | bool notprime[maxn]; 20 | 21 | struct factor { 22 | int prime, count; 23 | factor() :prime(0), count(0) {} 24 | factor(int p, int c) : prime(p), count(c) {} 25 | void print() { 26 | printf("(%d, %d)\n", prime, count); 27 | } 28 | }; 29 | // 厄尔多塞素数筛选法 30 | void Eratosthenes() { 31 | memset(notprime, false, sizeof(notprime)); 32 | notprime[1] = true; 33 | primes[0] = 0; 34 | for(int i = 2; i < maxn; i++) { 35 | if( !notprime[i] ) { 36 | primes[ ++primes[0] ] = i; 37 | //需要注意i*i超出整型后变成负数的问题,所以转化成 __int64 38 | for(ll j = (ll)i*i; j < maxn; j += i) { 39 | notprime[j] = true; 40 | } 41 | } 42 | } 43 | } 44 | 45 | // 因式分解 - 将n分解成素数幂乘积的形式 46 | // 举例: 47 | // 252 = (2^2) * (3^2) * (7^1) 48 | // 则 ans = [ (2,2), (3,2), (7,1) ] 49 | void Factorization(int n, vector & ans) { 50 | ans.clear(); 51 | if(n == 1) { 52 | return ; 53 | } 54 | // 素数试除 55 | for(int i = 1; i <= primes[0]; i++) { 56 | if(n % primes[i] == 0) { 57 | factor f(primes[i], 0); 58 | while( !(n % primes[i]) ) { 59 | n /= primes[i]; 60 | f.count ++; 61 | } 62 | ans.push_back(f); 63 | } 64 | if(n == 1) { 65 | return ; 66 | } 67 | } 68 | // 漏网之素数, 即大于MAXP的素数,最多1个 69 | ans.push_back( factor(n, 1) ); 70 | } 71 | 72 | int main() { 73 | Eratosthenes(); 74 | vector ans; 75 | Factorization(252, ans); 76 | printf("%d = \n", 252); 77 | for(int i = 0; i < ans.size(); i++) { 78 | ans[i].print(); 79 | } 80 | 81 | return 0; 82 | } 83 | 84 | 85 | -------------------------------------------------------------------------------- /数论/扩展欧拉定理 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数论/扩展欧拉定理 模板.cpp -------------------------------------------------------------------------------- /数论/拉宾米勒大数判素 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数论/拉宾米勒大数判素 模板.cpp -------------------------------------------------------------------------------- /数论/整数分块.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数论/整数分块.cpp -------------------------------------------------------------------------------- /数论/模幂循环节.cpp: -------------------------------------------------------------------------------- 1 | #define MAXN 10 2 | 3 | int F[MAXN+1], FPos[MAXN+1]; 4 | 5 | int f(int a, int b, int c) { 6 | int pre; 7 | memset(FPos, -1, sizeof(FPos)); 8 | F[0] = 1 % c; 9 | FPos[ F[0] ] = 0; 10 | for(int i = 1; i <= b; ++i) { 11 | F[i] = F[i-1] * a % c; 12 | int &pre = FPos[ F[i] ]; 13 | if( pre == -1) { 14 | pre = i; 15 | }else { 16 | int K = i - pre; 17 | int Index = ( b - pre ) % K + pre; 18 | return F[Index]; 19 | } 20 | } 21 | return F[b]; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /数论/欧拉函数 模板.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 欧拉函数 3 | n分解素因子表示为n = p1^e1 * p2^e2 * ... * pk^ek 4 | 则n的欧拉函数为 f(n) = (p1-1)p1^(e1-1) * (p2-1)p2^(e2-1) * ... * (pk-1)pk^(ek-1) 5 | Author: WhereIsHeroFrom 6 | Update Time: 2018-3-21 7 | Algorithm Complexity: O(sqrt(n)) 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | using namespace std; 14 | 15 | #define MAXP 65540 16 | #define LL __int64 17 | 18 | int primes[MAXP]; 19 | bool notprime[MAXP]; 20 | 21 | // 厄尔多塞素数筛选法 22 | void Eratosthenes() { 23 | memset(notprime, false, sizeof(notprime)); 24 | notprime[1] = true; 25 | primes[0] = 0; 26 | for(int i = 2; i < MAXP; i++) { 27 | if( !notprime[i] ) { 28 | primes[ ++primes[0] ] = i; 29 | //需要注意i*i超出整型后变成负数的问题,所以转化成 __int64 30 | for(LL j = (LL)i*i; j < MAXP; j += i) { 31 | notprime[j] = true; 32 | } 33 | } 34 | } 35 | } 36 | 37 | // 欧拉函数 - 获取小于n的数中与n互素的数的个数 38 | // 举例: 39 | // Phi(10) = 4 40 | // 即 1、3、7、9 总共4个 41 | int Phi(int n) { 42 | if(n == 1) { 43 | return 1; 44 | } 45 | int ans = 1; 46 | // 素数试除 47 | for(int i = 1; i <= primes[0]; i++) { 48 | int p = primes[i]; 49 | if(n % p == 0) { 50 | n /= p; 51 | ans *= (p - 1); 52 | while( !(n % p) ) { 53 | n /= p; 54 | ans *= p; 55 | } 56 | } 57 | if(n == 1) { 58 | return ans; 59 | } 60 | } 61 | return ans * (n - 1); 62 | } 63 | 64 | int main() { 65 | Eratosthenes(); 66 | printf("Phi(%d) = %d\n", 10, Phi(10)); 67 | return 0; 68 | } 69 | 70 | 71 | -------------------------------------------------------------------------------- /数论/欧拉函数 筛选法 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数论/欧拉函数 筛选法 模板.cpp -------------------------------------------------------------------------------- /数论/线性同余 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数论/线性同余 模板.cpp -------------------------------------------------------------------------------- /数论/逆元/扩展欧几里得 逆元 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数论/逆元/扩展欧几里得 逆元 模板.cpp -------------------------------------------------------------------------------- /数论/逆元/递推 逆元 模板.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | const int maxn = 3000010; 7 | #define ll long long 8 | 9 | int f[maxn]; 10 | 11 | int main() { 12 | int n, p; 13 | while(scanf("%d %d", &n, &p) != EOF) { 14 | f[1] = 1; 15 | for(int i = 2; i <= n; ++i) { 16 | f[i] = - (ll) (p/i) * f[p % i] % p; 17 | f[i] = (f[i] + p) % p; 18 | } 19 | for(int i = 1; i <= n; ++i) { 20 | printf("%d\n", f[i]); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /数论/递归枚举因子 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/数论/递归枚举因子 模板.cpp -------------------------------------------------------------------------------- /杂项/游标时间复杂度均摊.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/杂项/游标时间复杂度均摊.cpp -------------------------------------------------------------------------------- /杂项/蜂巢坐标系 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/杂项/蜂巢坐标系 模板.cpp -------------------------------------------------------------------------------- /杂项/输入加速.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/杂项/输入加速.cpp -------------------------------------------------------------------------------- /枚举/二分枚举/二分枚举 函数 模板.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/枚举/二分枚举/二分枚举 函数 模板.c -------------------------------------------------------------------------------- /枚举/二分枚举/二分枚举 数组 模板.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/枚举/二分枚举/二分枚举 数组 模板.c -------------------------------------------------------------------------------- /枚举/暴力枚举/线性枚举.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int isGreen(int val, int x) { 4 | return val > x; 5 | } 6 | 7 | int findFirstBiggerThan(int *arr, int arrSize, int x) { 8 | int i; 9 | for(i = 0; i < arrSize; ++i) { 10 | if( isGreen(arr[i], x) ) { 11 | return i; 12 | } 13 | } 14 | return arrSize; 15 | } 16 | 17 | int findFirstBiggerEqualThan(int *arr, int arrSize, int x) { 18 | int i; 19 | for(i = 0; i < arrSize; ++i) { 20 | if(arr[i] >= x) { 21 | return i; 22 | } 23 | } 24 | return arrSize; 25 | } 26 | 27 | int isGreenX(int val, int x) { 28 | return val >= x; 29 | } 30 | 31 | int findLastSmallThan(int *arr, int arrSize, int x) { 32 | int i; 33 | for(i = 0; i < arrSize; ++i) { 34 | if( isGreenX(arr[i], x) ) { 35 | return i - 1; 36 | } 37 | } 38 | return -1; 39 | } 40 | 41 | int findLastSmallEqualThan(int *arr, int arrSize, int x) { 42 | int i; 43 | for(i = arrSize-1; i >= 0; --i) { 44 | if(arr[i] <= x) { 45 | return i; 46 | } 47 | } 48 | return -1; 49 | } 50 | 51 | 52 | 53 | int main() { 54 | int arrSize = 9; 55 | int arr[] = {1, 3, 4, 6, 6, 6, 7, 8, 9}; 56 | 57 | int f1 = findFirstBiggerThan(arr, arrSize, 6); 58 | int f2 = findFirstBiggerEqualThan(arr, arrSize, 6); 59 | int f3 = findLastSmallThan(arr, arrSize, 6); 60 | int f4 = findLastSmallEqualThan(arr, arrSize, 6); 61 | 62 | printf("%d %d %d %d\n", f1, f2, f3, f4); 63 | 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /树/树的直径 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/树/树的直径 模板.cpp -------------------------------------------------------------------------------- /树/矩形树_最值 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/树/矩形树_最值 模板.cpp -------------------------------------------------------------------------------- /树/线段树_最值 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/树/线段树_最值 模板.cpp -------------------------------------------------------------------------------- /树状数组/一维树状数组 模板.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 树状数组 模板 3 | 4 | lowbit 5 | add 6 | sum 7 | 8 | Author: WhereIsHeroFrom 9 | Update Time: 2021-02-03 10 | Algorithm Complexity: O(log(n)) 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | using namespace std; 18 | 19 | //***************************************** 一维树状数组 模板 ***************************************** 20 | 21 | #define MAXV 100010 22 | #define ll long long 23 | 24 | ll c[MAXV]; 25 | 26 | void clear() { 27 | memset(c, 0, sizeof(c)); 28 | } 29 | 30 | int lowbit(int x) { 31 | return x & -x; 32 | } 33 | 34 | void add(int x, int maxn, ll v) { 35 | while (x <= maxn) { 36 | c[x] += v; 37 | x += lowbit(x); 38 | } 39 | } 40 | 41 | ll sum(int x) { 42 | ll s = 0; 43 | while (x >= 1) { 44 | s += c[x]; 45 | x ^= lowbit(x); 46 | } 47 | return s; 48 | } 49 | //***************************************** 一维树状数组 模板 ***************************************** -------------------------------------------------------------------------------- /树状数组/三维树状数组 模板.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | #define MAXN 110 6 | 7 | int c[MAXN][MAXN][MAXN]; 8 | int n; 9 | 10 | int lowbit(int x) { 11 | return x & -x; 12 | } 13 | 14 | void add(int x, int y, int z, int v) { 15 | v &= 1; 16 | if (v < 0) { 17 | v = -v; 18 | } 19 | 20 | int i, j, k; 21 | for (i = x; i <= n; i += lowbit(i)) { 22 | for (j = y; j <= n; j += lowbit(j)) { 23 | for (k = z; k <= n; k += lowbit(k)) { 24 | c[i][j][k] ^= v; 25 | } 26 | } 27 | } 28 | } 29 | 30 | int sum(int x, int y, int z) { 31 | int i, j, k; 32 | int s = 0; 33 | for (i = x; i; i -= lowbit(i)) { 34 | for (j = y; j; j -= lowbit(j)) { 35 | for (k = z; k; k -= lowbit(k)) { 36 | s ^= c[i][j][k]; 37 | } 38 | } 39 | } 40 | return s; 41 | } 42 | 43 | int main() { 44 | int m; 45 | while (scanf("%d %d", &n, &m) != EOF) { 46 | memset(c, 0, sizeof(c)); 47 | while (m--) { 48 | int tp; 49 | scanf("%d", &tp); 50 | if (!tp) { 51 | int x, y, z; 52 | scanf("%d %d %d", &x, &y, &z); 53 | printf("%d\n", sum(x, y, z)); 54 | } 55 | else { 56 | int x1, y1, z1, x2, y2, z2; 57 | scanf("%d %d %d %d %d %d", &x1, &y1, &z1, &x2, &y2, &z2); 58 | add(x1, y1, z1, 1); 59 | add(x2 + 1, y1, z1, -1); 60 | add(x1, y2 + 1, z1, -1); 61 | add(x1, y1, z2 + 1, -1); 62 | add(x2 + 1, y2 + 1, z1, 1); 63 | add(x1, y2 + 1, z2 + 1, 1); 64 | add(x2 + 1, y1, z2 + 1, 1); 65 | add(x2 + 1, y2 + 1, z2 + 1, -1); 66 | } 67 | } 68 | } 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /树状数组/二维树状数组 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/树状数组/二维树状数组 模板.cpp -------------------------------------------------------------------------------- /矩阵/矩阵 ijk 模板.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 矩阵二分快速幂 3 | 递推公式的神级加速,转换成矩阵幂求解; 4 | 矩阵相乘的最内层循环加和如果不溢出,则憋着不取模; 5 | Author: WhereIsHeroFrom 6 | Update Time: 2018-3-22 7 | Algorithm Complexity: O(m^3log(n)) 8 | */ 9 | 10 | #define MAXN 70 11 | #define MOD 1234567891 12 | #define LL __int64 13 | 14 | 15 | class Matrix { 16 | public: 17 | int n, m; 18 | LL d[MAXN][MAXN]; 19 | Matrix() { 20 | n = m = 0; 21 | int i, j; 22 | for(i = 0; i < MAXN; i++) { 23 | for(j = 0; j < MAXN; j++) { 24 | d[i][j] = 0; 25 | } 26 | } 27 | } 28 | Matrix operator *(const Matrix& other) { 29 | Matrix ret; 30 | ret.n = n; 31 | ret.m = other.m; 32 | int i, j, k; 33 | for(j = 0; j < ret.m; j++) { 34 | for(i = 0; i < ret.n; i++) { 35 | ret.d[i][j] = 0; 36 | for(k = 0; k < m; k++) { 37 | ret.d[i][j] += d[i][k] * other.d[k][j]; 38 | if (ret.d[i][j] >= MOD) 39 | ret.d[i][j] %= MOD; 40 | } 41 | } 42 | } 43 | return ret; 44 | } 45 | 46 | Matrix Identity(int _n) { 47 | Matrix I; 48 | I.n = I.m = _n; 49 | int i, j; 50 | for(i = 0; i < _n; i++) { 51 | for(j = 0; j < _n; j++) { 52 | I.d[i][j] = (i == j) ? 1 : 0; 53 | } 54 | } 55 | return I; 56 | } 57 | 58 | Matrix getPow(unsigned __int64 e) { 59 | Matrix tmp = *this; 60 | Matrix ret = Identity(n); 61 | while(e) { 62 | if(e & 1) { 63 | ret = ret * tmp; 64 | } 65 | e >>= 1; 66 | tmp = tmp * tmp; 67 | } 68 | return ret; 69 | } 70 | 71 | // | A A | 72 | // | O I | 73 | // 扩展矩阵用于求A + A^2 + A^3 + ... + A^n 74 | Matrix getExtendMatrix() { 75 | Matrix ret; 76 | ret.n = ret.m = n * 2; 77 | ret.copyMatrix( *this, 0, 0); 78 | ret.copyMatrix( *this, 0, n); 79 | ret.copyMatrix( Identity(n), n, n); 80 | return ret; 81 | } 82 | 83 | // 将矩阵A拷贝到当期矩阵的(r, c)位置 84 | void copyMatrix(Matrix A, int r, int c) { 85 | for(int i = r; i < r + A.n; i++) { 86 | for(int j = c; j < c + A.n; j++) { 87 | d[i][j] = A.d[i-r][j-c]; 88 | } 89 | } 90 | } 91 | 92 | void Print() { 93 | int i, j; 94 | for(i = 0; i < n; i++) { 95 | for(j = 0; j < m; j++) { 96 | printf("%d ", d[i][j]); 97 | } 98 | puts(""); 99 | } 100 | } 101 | }; 102 | -------------------------------------------------------------------------------- /矩阵/矩阵 ikj 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/矩阵/矩阵 ikj 模板.cpp -------------------------------------------------------------------------------- /矩阵/矩阵乘法 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/矩阵/矩阵乘法 模板.cpp -------------------------------------------------------------------------------- /矩阵/矩阵乘法.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/矩阵/矩阵乘法.bmp -------------------------------------------------------------------------------- /组合数学/Polya环形计数 模板.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Polya环形计数 3 | 问题:m种颜色给n个对象染色,且这个n个对象呈环形排列。旋转相同的方案记为一种,求染色的方案数。 4 | 解法:n个对象旋转产生n种置换,旋转i格的置换的循环节为gcd(n,i),则方案数为 L=sum{m^gcd(n,i)| 0<=i 15 | #include 16 | #include 17 | #include 18 | using namespace std; 19 | 20 | 21 | #define MAXP 65540 22 | #define MOD 9937 23 | #define LL __int64 24 | 25 | int primes[MAXP]; 26 | bool notprime[MAXP]; 27 | 28 | struct factor { 29 | int prime, count; 30 | factor() { 31 | } 32 | factor(int p, int c) { 33 | prime = p; 34 | count = c; 35 | } 36 | void print() { 37 | printf("(%d, %d)\n", prime, count); 38 | } 39 | }; 40 | 41 | // 厄尔多塞素数筛选法 42 | void Eratosthenes() { 43 | memset(notprime, false, sizeof(notprime)); 44 | notprime[1] = true; 45 | primes[0] = 0; 46 | for(int i = 2; i < MAXP; i++) { 47 | if( !notprime[i] ) { 48 | primes[ ++primes[0] ] = i; 49 | //需要注意i*i超出整型后变成负数的问题,所以转化成 __int64 50 | for(LL j = (LL)i*i; j < MAXP; j += i) { 51 | notprime[j] = true; 52 | } 53 | } 54 | } 55 | } 56 | 57 | // 因式分解 - 将n分解成素数幂乘积的形式 58 | // 举例: 59 | // 252 = (2^2) * (3^2) * (7^1) 60 | // 则 ans = [ (2,2), (3,2), (7,1) ] 61 | void Factorization(int n, vector & ans) { 62 | ans.clear(); 63 | if(n == 1) { 64 | return ; 65 | } 66 | // 素数试除 67 | for(int i = 1; i <= primes[0]; i++) { 68 | if(n % primes[i] == 0) { 69 | factor f(primes[i], 0); 70 | while( !(n % primes[i]) ) { 71 | n /= primes[i]; 72 | f.count ++; 73 | } 74 | ans.push_back(f); 75 | } 76 | if(n == 1) { 77 | return ; 78 | } 79 | } 80 | // 漏网之素数, 即大于MAXP的素数,最多1个 81 | ans.push_back( factor(n, 1) ); 82 | } 83 | 84 | int power(int a, int b, int c) { 85 | if(b == 0) { 86 | return 1 % c; 87 | } 88 | int x = power(a*a%c, b/2, c); 89 | if(b&1) 90 | x = x * a % c; 91 | return x; 92 | } 93 | 94 | // n颗珠子、m种颜色 95 | int n, m; 96 | // 环形项链的方案数 97 | int ans; 98 | 99 | int polyaPart(int fac, int facEula) { 100 | return facEula % MOD * power(m % MOD, n/fac, MOD) % MOD; 101 | } 102 | 103 | // 因式分解后递归枚举所有因子 104 | // 枚举因子的同时,枚举每个因子的欧拉函数 105 | void emunFactor(int depth, vector fact, int now, int eula) { 106 | if(fact.size() == depth) { 107 | //printf("%d %d\n", now, eula); 108 | ans = (ans + polyaPart(now, eula) ) % MOD; 109 | return ; 110 | } 111 | factor &f = fact[depth]; 112 | int i; 113 | emunFactor(depth+1, fact, now, eula); 114 | eula *= (f.prime - 1); 115 | now *= f.prime; 116 | for(i = 1; i <= f.count; ++i) { 117 | emunFactor(depth+1, fact, now, eula); 118 | now *= f.prime; 119 | eula *= f.prime; 120 | } 121 | } 122 | 123 | 124 | int main() { 125 | Eratosthenes(); 126 | int i, t; 127 | while(scanf("%d %d", &n, &m)!=EOF) { 128 | if(m==0) { 129 | printf("0\n"); 130 | continue; 131 | } 132 | ans = 0; 133 | vector v; 134 | Factorization(n, v); 135 | emunFactor(0, v, 1, 1); 136 | 137 | n %= MOD; 138 | for(i = 1; ; ++i) { 139 | if(n*i % MOD == ans) { 140 | break; 141 | } 142 | } 143 | printf("%d\n", i); 144 | } 145 | return 0; 146 | } 147 | -------------------------------------------------------------------------------- /组合数学/多重集排列 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/组合数学/多重集排列 模板.cpp -------------------------------------------------------------------------------- /组合数学/置换群 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/组合数学/置换群 模板.cpp -------------------------------------------------------------------------------- /计算几何/半平面交 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/计算几何/半平面交 模板.cpp -------------------------------------------------------------------------------- /计算几何/模拟退火 模板.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 模拟退火 3 | 1、初温控制 尽量取最大值 4 | 2、初始点集 可以根据问题特点 取1(优先考虑)个或多个 5 | 3、最小温度精度 控制在问题需要的精度的下一个数量级 6 | 4、候选点集尽量取得能力范围之内的多者 7 | 5、最重要:模拟退火的时候遇到较差的解,根据概率性选择较差解;当然,也要根据实际情况放弃较差解。 8 | 9 | Author: WhereIsHeroFrom 10 | Update Time: 2018-3-31 11 | Algorithm Complexity: 取决于下降率的非2为底的log级复杂度 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | using namespace std; 20 | 21 | #define PI acos(-1.0) 22 | #define eps 1e-6 23 | typedef double Type; 24 | 25 | // 三值函数 26 | int threeValue(Type d) { 27 | if(fabs(d) < 1e-6) 28 | return 0; 29 | return d > 0 ? 1 : -1; 30 | } 31 | 32 | class Point3D { 33 | Type x, y, z; 34 | 35 | public: 36 | Point3D(){ 37 | } 38 | Point3D(Type _x, Type _y, Type _z): x(_x), y(_y), z(_z) {} 39 | void read() { 40 | scanf("%lf %lf", &x, &y); 41 | z = 0; 42 | //scanf("%lf %lf %lf", &x, &y, &z); 43 | } 44 | void print() { 45 | printf("\n", x, y, z); 46 | } 47 | inline Type getx() { return x; } 48 | inline Type gety() { return y; } 49 | inline Type getz() { return z; } 50 | bool inRange(Point3D& max) const; 51 | Point3D operator+(const Point3D& other) const; 52 | Point3D operator-(const Point3D& other) const; 53 | Point3D operator*(const double &k) const; 54 | Point3D operator/(const double &k) const; 55 | Type operator*(const Point3D& other) const; 56 | double len(); 57 | Point3D normalize(); 58 | }; 59 | 60 | typedef Point3D Vector3D; 61 | 62 | double Vector3D::len() { 63 | return sqrt(x*x + y*y + z*z); 64 | } 65 | 66 | Point3D Vector3D::normalize() { 67 | double l = len(); 68 | if(threeValue(l)) { 69 | x /= l; 70 | y /= l; 71 | z /= l; 72 | } 73 | return *this; 74 | } 75 | 76 | bool Point3D::inRange(Point3D& max) const { 77 | return (0<=x&&x<=max.x) && (0<=y&&y<=max.y) && (0<=z&&z<=max.z); 78 | } 79 | 80 | Point3D Point3D::operator+(const Point3D& other) const { 81 | return Point3D(x + other.x, y + other.y, z + other.z); 82 | } 83 | 84 | Point3D Point3D::operator-(const Point3D& other) const { 85 | return Point3D(x - other.x, y - other.y, z - other.z); 86 | } 87 | 88 | Point3D Point3D::operator *(const double &k) const { 89 | return Point3D(x * k, y * k, z * k); 90 | } 91 | 92 | Point3D Point3D::operator /(const double &k) const { 93 | return (*this) * (1/k); 94 | } 95 | 96 | Type Point3D::operator*(const Point3D& other) const { 97 | return x*other.x + y*other.y + z*other.z; 98 | } 99 | 100 | 101 | #define MAXN 1010 102 | #define MAXC 1000 103 | #define INF 1000000000.0 104 | 105 | struct Point3DSet { 106 | int n; 107 | Point3D p[MAXN]; 108 | }; 109 | 110 | /* 111 | 模拟退火-模板 112 | 最远的最近距离 113 | */ 114 | class simulatedAnnealing { 115 | // 稳态(最低)温度 116 | static const double minTemperature; 117 | // 温度下降率 118 | static const double deltaTemperature; 119 | // 并行候选解个数 120 | static const int solutionCount; 121 | // 每个解的迭代次数 122 | static const int candidateCount; 123 | private: 124 | Point3D bound; 125 | Point3D x[MAXC]; 126 | Point3DSet pointSet; 127 | double temperature; 128 | 129 | bool valid(const Point3D& pt); 130 | double randIn01(); 131 | Point3D getRandomPoint(); 132 | Vector3D getRandomDirection(); 133 | Point3D getNext(const Point3D& now); 134 | public: 135 | void start(double T, Point3D B, Point3DSet& pointSet); 136 | double evaluateFunc(const Point3D& pt); 137 | Point3D getSolution(); 138 | static simulatedAnnealing& Instance(); 139 | }; 140 | 141 | // 四个调整参数 142 | // 稳态(最低)温度 143 | const double simulatedAnnealing::minTemperature = 1e-2; 144 | // 温度下降率 145 | const double simulatedAnnealing::deltaTemperature = 0.95; 146 | // 并行候选解个数 147 | const int simulatedAnnealing::solutionCount = 10; 148 | // 每个解的迭代次数 149 | const int simulatedAnnealing::candidateCount = 30; 150 | 151 | bool simulatedAnnealing::valid(const Point3D& pt) { 152 | return pt.inRange(bound); 153 | } 154 | 155 | double simulatedAnnealing::randIn01() { 156 | return (rand() + 0.0) / RAND_MAX; 157 | } 158 | 159 | /* 160 | 估价函数,估值越小越优 161 | 不同问题,基本只需要修改估价函数,这个是 最远的最近距离 162 | */ 163 | double simulatedAnnealing::evaluateFunc(const Point3D& pt) { 164 | // TODO 165 | // 最小距离 越大越优,所以估值取相反数 166 | double minDist = INF; 167 | for(int i = 0; i < pointSet.n; ++i) { 168 | double dist = (pointSet.p[i] - pt).len(); 169 | if(dist < minDist) 170 | minDist = dist; 171 | } 172 | return - minDist; 173 | } 174 | 175 | /* 176 | 随机一个[0 - bound]的点,如果要求有负数点,请将整个坐标轴进行平移 177 | */ 178 | Point3D simulatedAnnealing::getRandomPoint() { 179 | return Point3D(bound.getx() * randIn01(), bound.gety() * randIn01(), 0);//bound.getz() * randIn01()); 180 | } 181 | 182 | /* 183 | 随机一个方向,注意方向可以是任何方向,别忘了负数 184 | */ 185 | Vector3D simulatedAnnealing::getRandomDirection() { 186 | Vector3D v(randIn01()-0.5, randIn01()-0.5, 0);//randIn01()-0.5); 187 | return v.normalize(); 188 | } 189 | 190 | Point3D simulatedAnnealing::getNext(const Point3D& now) { 191 | return now + getRandomDirection() * temperature; 192 | } 193 | 194 | /* 195 | 模拟退火 196 | */ 197 | void simulatedAnnealing::start(double T, Point3D B, Point3DSet& PS) { 198 | // 0.初始化温度 199 | temperature = T; 200 | bound = B; 201 | pointSet = PS; 202 | int i, j; 203 | 204 | // 1.随机生成solutionCount个初始解 205 | for(i = 0; i < solutionCount; ++i) { 206 | x[i] = getRandomPoint(); 207 | } 208 | 209 | while (temperature > minTemperature) { 210 | // 2.对每个当前解进行最优化选择 211 | for(i = 0; i < solutionCount; ++i) { 212 | double nextEval = INF; 213 | Point3D nextOpt; 214 | // 3.对于每个当前解,随机选取附近的candidateCount个点,并且将最优的那个解保留 215 | for(j = 0; j < candidateCount; ++j) { 216 | Point3D next = getNext(x[i]); 217 | if(!valid(next)) { 218 | continue; 219 | } 220 | double Eval = evaluateFunc(next); 221 | if(Eval < nextEval) { 222 | nextEval = Eval; 223 | nextOpt = next; 224 | } 225 | } 226 | 227 | // 4.没有生成可行解 228 | if(nextEval >= INF) 229 | continue; 230 | 231 | // 5.计算生成的最优解和原来的解进行比较 232 | double deltaEval = evaluateFunc(nextOpt) - evaluateFunc(x[i]); 233 | if(deltaEval < 0) { 234 | // 6.比原来的解更优,直接替换 235 | x[i] = nextOpt; 236 | }else { 237 | // 7.没有原来的解优,则以一定概率进行接收 238 | // 这个概率上限会越来越小,直到最后趋近于0 239 | // 理论上,这个分支也可能不考虑 240 | if( randIn01() < exp(-deltaEval/temperature) ) { 241 | x[i] = nextOpt; 242 | } 243 | } 244 | } 245 | temperature *= deltaTemperature; 246 | } 247 | //for(i = 0; i < solutionCount; ++i) x[i].print(); 248 | } 249 | 250 | Point3D simulatedAnnealing::getSolution() { 251 | int retIdx = 0; 252 | for (int i = 1; i < solutionCount; ++i) { 253 | if(evaluateFunc(x[i]) < evaluateFunc(x[retIdx])) { 254 | retIdx = i; 255 | } 256 | } 257 | return x[retIdx]; 258 | } 259 | 260 | simulatedAnnealing& simulatedAnnealing::Instance() { 261 | static simulatedAnnealing inst; 262 | return inst; 263 | } 264 | -------------------------------------------------------------------------------- /计算几何/解析几何_线段交点.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/计算几何/解析几何_线段交点.cpp -------------------------------------------------------------------------------- /计算几何/计算几何 3D点的旋转.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/计算几何/计算几何 3D点的旋转.cpp -------------------------------------------------------------------------------- /计算几何/计算几何 二维凸包.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | const int MAXP = 100010; 9 | const double eps = 1e-10; 10 | #define INT_POINT 11 | 12 | #ifdef INT_POINT 13 | typedef int PointType; 14 | typedef long long MultiplyType; // 由于乘法可能导致 int 溢出,所以需要定义一种乘法后的类型(平方、叉乘、点乘) 15 | #else 16 | typedef double PointType; 17 | typedef double MultiplyType; 18 | #endif 19 | typedef int PointIndex; 20 | 21 | // 小于 22 | bool ST(PointType a, PointType b) { 23 | #ifdef INT_POINT 24 | return a < b; 25 | #else 26 | return a - b < -eps; 27 | #endif 28 | } 29 | 30 | // 等于 31 | bool EQ(PointType a, PointType b) { 32 | #ifdef INT_POINT 33 | return a == b; 34 | #else 35 | return fabs(a - b) < eps; 36 | #endif 37 | } 38 | 39 | // 大于 40 | bool LT(PointType a, PointType b) { 41 | return !ST(a, b) && !EQ(a, b); 42 | } 43 | 44 | int TernaryFunc(double v) { 45 | if (EQ(v, 0)) { 46 | return 0; 47 | } 48 | return ST(v, 0) ? -1 : 1; 49 | } 50 | 51 | MultiplyType SQR(MultiplyType x) { 52 | return x * x; 53 | } 54 | 55 | class Point2D { 56 | public: 57 | Point2D() : x_(0), y_(0) {} 58 | Point2D(PointType x, PointType y) : x_(x), y_(y) {} 59 | 60 | bool zero() const; 61 | Point2D operator + (const Point2D& pt) const; 62 | Point2D operator - (const Point2D& pt) const; 63 | MultiplyType cross(const Point2D& pt) const; 64 | bool operator < (const Point2D& pt) const; 65 | bool operator == (const Point2D& pt) const; 66 | 67 | 68 | MultiplyType distSquare(const Point2D& pt) const; 69 | static bool angleCmp(const Point2D& a, const Point2D& b); 70 | void calculateAngle(const Point2D& o); 71 | 72 | void read(int idx); 73 | double getAngle() const; 74 | private: 75 | PointType x_, y_; 76 | double angle_; // 相对于左下角点的极角 77 | double distSqr_; // 相对于左下角点的距离平方 78 | int index_; // 在原数组的下标,方便索引用 79 | }; 80 | typedef Point2D Vector2D; 81 | 82 | bool Point2D::zero() const { 83 | return EQ(x_, 0) && EQ(y_, 0); 84 | } 85 | 86 | Point2D Point2D::operator + (const Point2D& pt) const { 87 | return Point2D(x_ + pt.x_, y_ + pt.y_); 88 | } 89 | 90 | Point2D Point2D::operator - (const Point2D& pt) const { 91 | return Point2D(x_ - pt.x_, y_ - pt.y_); 92 | } 93 | 94 | MultiplyType Vector2D::cross(const Vector2D& pt) const { 95 | return (MultiplyType)x_ * pt.y_ - (MultiplyType)y_ * pt.x_; 96 | } 97 | 98 | bool Point2D::operator<(const Point2D& pt) const { 99 | // 1. 第一关键字: y 小的 100 | // 2. 第二关键字: x 小的 101 | if (!EQ(y_, pt.y_)) { 102 | return ST(y_, pt.y_); 103 | } 104 | return ST(x_, pt.x_); 105 | } 106 | 107 | bool Point2D::operator==(const Point2D& pt) const { 108 | return (*this - pt).zero(); 109 | } 110 | 111 | MultiplyType Point2D::distSquare(const Point2D& pt) const { 112 | Point2D t = *this - pt; 113 | return SQR(t.x_) + SQR(t.y_); 114 | } 115 | 116 | bool Point2D::angleCmp(const Point2D& a, const Point2D& b) { 117 | if (fabs(a.angle_ - b.angle_) < eps) { 118 | return a.distSqr_ < b.distSqr_; 119 | } 120 | return a.angle_ < b.angle_; 121 | } 122 | 123 | void Point2D::calculateAngle(const Point2D& o) { 124 | Point2D t = *this - o; 125 | if (t.zero()) { 126 | // 该情况下 atan2 是 undefined 的,需要单独处理 127 | angle_ = 0; 128 | distSqr_ = 0; 129 | } 130 | else { 131 | angle_ = atan2(0.0 + t.y_, 0.0 + t.x_); // 这里 y >= 0 是能保证的,所以值在 [0, PI] 之间 132 | distSqr_ = distSquare(o); 133 | } 134 | } 135 | 136 | void Point2D::read(int idx) { 137 | #ifdef INT_POINT 138 | scanf("%d %d", &x_, &y_); 139 | #else 140 | scanf("%lf %lf", &x_, &y_); 141 | #endif 142 | index_ = idx; 143 | } 144 | 145 | double Point2D::getAngle() const { 146 | return angle_; 147 | } 148 | 149 | class Polygon { 150 | private: 151 | void grahamScan_Pre(); // 计算凸包前的准备工作 152 | public: 153 | bool isPoint() const; // 求完凸包以后判断是否是一个点 154 | bool isLine() const; // 求完凸包以后判断是否是一条线 155 | void grahamScan(bool flag, Polygon& ret); 156 | double area(); 157 | double length(); 158 | bool read(); 159 | 160 | public: 161 | bool check(); // 根据不同情况提供的开放检查接口 162 | private: 163 | int n_; 164 | Point2D point_[MAXP]; 165 | PointIndex stack_[MAXP]; 166 | int top_; 167 | }; 168 | 169 | bool Polygon::isPoint() const { 170 | if (n_ <= 1) { 171 | return true; 172 | } 173 | return point_[n_ - 1] == point_[0]; 174 | } 175 | 176 | bool Polygon::isLine() const { 177 | if (n_ <= 2) { 178 | return true; 179 | } 180 | return (TernaryFunc((point_[n_ - 1] - point_[0]).cross(point_[1] - point_[0])) == 0); 181 | } 182 | 183 | 184 | void Polygon::grahamScan_Pre() 185 | { 186 | // 1. 首先将最下面的那个点(如果y相同,则取最左边)找出来放到 point_[0] 的位置 187 | for (int i = 1; i < n_; ++i) { 188 | if (point_[i] < point_[0]) { 189 | swap(point_[i], point_[0]); 190 | } 191 | } 192 | // 2. 对 point_[0] 计算极角 193 | for (int i = 1; i < n_; ++i) { 194 | point_[i].calculateAngle(point_[0]); 195 | } 196 | // 3. 极角排序 197 | sort(point_ + 1, point_ + n_, Point2D::angleCmp); 198 | } 199 | 200 | 201 | // flag 是否算上边上的点、重复点 202 | void Polygon::grahamScan(bool flag, Polygon& ret) { 203 | 204 | // 找到极值坐标系原点,并且按照极角排序 205 | grahamScan_Pre(); 206 | 207 | // 栈底永远是那个极值坐标系的原点 208 | top_ = 0; 209 | stack_[top_++] = 0; 210 | 211 | for (int i = 1; i < n_; ++i) { 212 | if ((point_[i] - point_[0]).zero()) { 213 | // 和原点有重合,即多点重复 214 | if (flag) { 215 | stack_[top_++] = i; 216 | } 217 | continue; 218 | } 219 | 220 | while (top_ >= 2) { 221 | Point2D p1 = point_[stack_[top_ - 1]] - point_[stack_[top_ - 2]]; 222 | Point2D p2 = point_[i] - point_[stack_[top_ - 2]]; 223 | MultiplyType crossRet = p1.cross(p2); 224 | // 如果选择边上的点,那么叉乘结果大于等于0是允许的 225 | // 如果不选择边上的点,那么叉乘结果大于0是允许的 226 | if (flag && TernaryFunc(crossRet) < 0 || !flag && TernaryFunc(crossRet) <= 0) 227 | --top_; 228 | else 229 | break; 230 | } 231 | stack_[top_++] = i; 232 | } 233 | 234 | // 结果输出 235 | ret.n_ = top_; 236 | for (int i = 0; i < top_; ++i) { 237 | ret.point_[i] = point_[stack_[i]]; 238 | } 239 | 240 | if (ret.isPoint() || ret.isLine()) { 241 | // 是点或者线的情况不进行补点 242 | return; 243 | } 244 | 245 | // Graham 扫描算法的改进,如果要考虑边上的点 246 | // 那么最后一条多边形的回边 247 | if (flag) { 248 | for (int i = n_ - 1; i >= 0; --i) { 249 | if (point_[i] == ret.point_[top_-1]) continue; 250 | if (fabs(point_[i].getAngle() - ret.point_[top_ - 1].getAngle()) < eps) { 251 | // 极角相同的点必须补回来 252 | ret.point_[ret.n_++] = point_[i]; 253 | } 254 | else break; 255 | } 256 | } 257 | } 258 | 259 | double Polygon::area() { 260 | double ans = 0; 261 | point_[n_] = point_[0]; 262 | for (int i = 1; i < n_; ++i) { 263 | ans += (point_[i] - point_[0]).cross(point_[i+1] - point_[0]); 264 | } 265 | return ans / 2; 266 | } 267 | 268 | double Polygon::length() { 269 | if (n_ == 1) { 270 | return 0; 271 | } 272 | else if (n_ == 2) { 273 | return sqrt(0.0 + point_[1].distSquare(point_[0])); 274 | } 275 | double ans = 0; 276 | point_[n_] = point_[0]; 277 | for (int i = 0; i < n_; ++i) { 278 | ans += sqrt( 0.0 + point_[i].distSquare(point_[i + 1]) ); 279 | } 280 | return ans; 281 | } 282 | 283 | bool Polygon::read() { 284 | int ret = scanf("%d", &n_); 285 | if (ret == EOF || n_ == 0) { 286 | return false; 287 | } 288 | for (int i = 0; i < n_; ++i) { 289 | point_[i].read(i); 290 | } 291 | return true; 292 | } 293 | 294 | bool Polygon::check() { 295 | int t = 1; 296 | for (int i = 1; i < n_; ++i) { 297 | if (point_[i] == point_[i - 1]) { 298 | }else { 299 | point_[t++] = point_[i]; 300 | } 301 | } 302 | n_ = t; 303 | 304 | point_[n_] = point_[0]; 305 | 306 | if (isLine() || isPoint()) { 307 | return false; 308 | } 309 | 310 | int cur = 0, minv; 311 | while (cur < n_) { 312 | int cnt = 0; 313 | for (int j = cur + 1; j < n_; ++j) { 314 | if (TernaryFunc((point_[j] - point_[cur]).cross(point_[j + 1] - point_[cur])) == 0) { 315 | cnt++; 316 | minv = j; 317 | } 318 | else break; 319 | } 320 | if (cnt == 0) return false; 321 | cur = minv + 1; 322 | } 323 | return true; 324 | } 325 | 326 | Polygon P, Res; 327 | 328 | int main() { 329 | int t; 330 | scanf("%d", &t); 331 | while (t--) { 332 | P.read(); 333 | P.grahamScan(true, Res); 334 | printf("%s\n", Res.check() ? "YES":"NO"); 335 | } 336 | return 0; 337 | } 338 | -------------------------------------------------------------------------------- /计算几何/计算几何 圆和多边形的交 模板.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | const int MAXP = 110000; 8 | #define PI acos(-1.0) 9 | #define eps 1e-6 10 | #define LL __int64 11 | typedef double Type; 12 | 13 | // 三值函数 14 | int threeValue(Type d) { 15 | if(fabs(d) < 1e-6) 16 | return 0; 17 | return d > 0 ? 1 : -1; 18 | } 19 | 20 | // 两线段交点类型 21 | enum SegCrossType { 22 | SCT_NONE = 0, 23 | SCT_CROSS = 1, // 正常相交 24 | SCT_ENDPOINT_ON = 2, // 其中一条线段的端点在另一条上 25 | }; 26 | 27 | class Point2D { 28 | Type x, y; 29 | 30 | public: 31 | Point2D(){ 32 | } 33 | Point2D(Type _x, Type _y): x(_x), y(_y) {} 34 | void read() { 35 | scanf("%lf %lf", &x, &y); 36 | } 37 | void print() { 38 | printf("<%lf, %lf>\n", x, y); 39 | } 40 | Type getx() const { return x; } 41 | Type gety() const { return y; } 42 | Point2D turnLeft(); 43 | Point2D turnRight(); 44 | double angle(); 45 | Point2D operator+(const Point2D& other) const; 46 | Point2D operator-(const Point2D& other) const; 47 | Point2D operator*(const double &k) const; 48 | Point2D operator/(const double &k) const; 49 | Type operator*(const Point2D& other) const; 50 | bool operator <(const Point2D &p) const; 51 | Type X(const Point2D& other) const; 52 | double len(); 53 | Point2D normalize(); 54 | bool sameSide(Point2D a, Point2D b); 55 | }; 56 | 57 | typedef Point2D Vector2D; 58 | 59 | double Vector2D::len() { 60 | return sqrt(x*x + y*y); 61 | } 62 | 63 | Point2D Vector2D::normalize() { 64 | double l = len(); 65 | if(threeValue(l)) { 66 | x /= l; 67 | y /= l; 68 | } 69 | return *this; 70 | } 71 | 72 | Point2D Point2D::turnLeft() { 73 | return Point2D(-y, x); 74 | } 75 | Point2D Point2D::turnRight() { 76 | return Point2D(y, -x); 77 | } 78 | double Point2D::angle() { 79 | return atan2(y, x); 80 | } 81 | 82 | Point2D Point2D::operator+(const Point2D& other) const { 83 | return Point2D(x + other.x, y + other.y); 84 | } 85 | 86 | Point2D Point2D::operator-(const Point2D& other) const { 87 | return Point2D(x - other.x, y - other.y); 88 | } 89 | 90 | Point2D Point2D::operator *(const double &k) const { 91 | return Point2D(x * k, y * k); 92 | } 93 | 94 | Point2D Point2D::operator /(const double &k) const { 95 | return Point2D(x / k, y / k); 96 | } 97 | 98 | bool Point2D::operator <(const Point2D &p) const { 99 | return y + eps < p.y || ( y < p.y + eps && x + eps < p.x ); 100 | } 101 | 102 | // !!!!注意!!!! 103 | // 如果Type为int,则乘法可能导致int32溢出,小心谨慎 104 | // 点乘 105 | Type Point2D::operator*(const Point2D& other) const { 106 | return x*other.x + y*other.y; 107 | } 108 | // 叉乘 109 | Type Point2D::X(const Point2D& other) const { 110 | return x*other.y - y*other.x; 111 | } 112 | 113 | // 向量a和b是否在当前向量的同一边 114 | bool Point2D::sameSide(Point2D a, Point2D b) { 115 | // 请保证 当前向量和a、b向量的起点一致 116 | return threeValue(X(a)) * threeValue(X(b)) == 1; 117 | } 118 | 119 | class Segment2D { 120 | Point2D s, t; 121 | public: 122 | Segment2D() {} 123 | Segment2D(const Point2D& _s, const Point2D& _t) : s(_s), t(_t) { 124 | } 125 | void read() { 126 | s.read(); 127 | t.read(); 128 | } 129 | Type sXt() const { 130 | return s.X(t); 131 | } 132 | 133 | Vector2D vector() const { 134 | return t - s; 135 | } 136 | 137 | // 定点叉乘 138 | // 外部找一点p,然后计算 (p-s)×(t-s) 139 | Type cross(const Point2D& p) const { 140 | return (p - s).X(t - s); 141 | } 142 | 143 | // 跨立测验 144 | // 将当前线段作为一条很长的直线,检测线段other是否跨立在这条直线的两边 145 | bool lineCross(const Segment2D& other) const; 146 | 147 | // 点是否在线段上 148 | bool pointOn(const Point2D& p) const; 149 | 150 | // 线段判交 151 | // 1.通过跨立测验 152 | // 2.点是否在线段上 153 | SegCrossType segCross(const Segment2D& other); 154 | }; 155 | 156 | bool Segment2D::lineCross(const Segment2D& other) const { 157 | return threeValue(cross(other.s)) * threeValue(cross(other.t)) == -1; 158 | } 159 | 160 | bool Segment2D::pointOn(const Point2D& p) const { 161 | // 满足两个条件: 162 | // 1.叉乘为0, (p-s)×(t-s) == 0 163 | // 2.点乘为-1或0,(p-s)*(p-t) <= 0 164 | return cross(p) == 0 && (p-s)*(p-t) <= 0; 165 | } 166 | 167 | SegCrossType Segment2D::segCross(const Segment2D& other) { 168 | if(this->lineCross(other) && other.lineCross(*this)) { 169 | // 两次跨立都成立,则必然相交与一点 170 | return SCT_CROSS; 171 | } 172 | // 任意一条线段的某个端点是否在其中一条线段上,四种情况 173 | if(pointOn(other.s) || pointOn(other.t) || 174 | other.pointOn(s) || other.pointOn(t) ) { 175 | return SCT_ENDPOINT_ON; 176 | } 177 | return SCT_NONE; 178 | } 179 | 180 | class Line2D { 181 | public: 182 | Point2D a, b; 183 | Line2D() {} 184 | Line2D(const Point2D& _a, const Point2D& _b): a(_a), b(_b) { 185 | } 186 | Point2D getCrossPoint(const Line2D& ); 187 | bool isParallelTo(const Line2D& ); 188 | }; 189 | 190 | // 两条不平行的直线必有交点 191 | // 利用叉乘求面积法的相似三角形比值得出交点 192 | Point2D Line2D::getCrossPoint(const Line2D& other) { 193 | double SA = (other.a - a).X(b - a); 194 | double SB = (b - a).X(other.b - a); 195 | return (other.b * SA + other.a * SB) / (SA + SB); 196 | } 197 | 198 | bool Line2D::isParallelTo(const Line2D& other) { 199 | return !threeValue( (b-a).X(other.b - other.a) ); 200 | } 201 | 202 | class line2DTriple { 203 | public: 204 | // ax + by + c = 0; 205 | Type a, b, c; 206 | 207 | line2DTriple(){} 208 | line2DTriple(const Point2D& _a, const Point2D& _b) { 209 | getFromSegment2D(Segment2D(_a, _b)); 210 | } 211 | line2DTriple(const Segment2D& s) { 212 | getFromSegment2D(s); 213 | } 214 | void getFromSegment2D(const Segment2D&); 215 | double getPointDist(const Point2D& p); 216 | }; 217 | 218 | void line2DTriple::getFromSegment2D(const Segment2D& seg) { 219 | Vector2D v = seg.vector(); 220 | a = - v.gety(); 221 | b = v.getx(); 222 | c = seg.sXt(); 223 | //Print(); 224 | } 225 | 226 | double line2DTriple::getPointDist(const Point2D& p) { 227 | return fabs(a*p.getx() + b*p.gety() + c) / sqrt(a*a+b*b); 228 | } 229 | 230 | struct Polygon { 231 | int n; 232 | Point2D p[MAXP]; 233 | 234 | void print(); 235 | double area(); 236 | void getConvex(Polygon &c); 237 | bool isConvex(); 238 | bool isPointInConvex(const Point2D &P); 239 | Point2D CalcBary(); 240 | void convertToCounterClockwise(); 241 | }; 242 | 243 | void Polygon::print() { 244 | int i; 245 | printf("%d\n", n); 246 | for(i = 0; i < n; ++i) { 247 | p[i].print(); 248 | } 249 | } 250 | 251 | double Polygon::area() { 252 | double sum = 0; 253 | p[n] = p[0]; 254 | for ( int i = 0 ; i < n; i ++ ) 255 | sum += p[i].X(p[i + 1]); 256 | return sum / 2; 257 | } 258 | 259 | // 求凸包 260 | void Polygon::getConvex(Polygon &c) { 261 | sort(p, p + n); 262 | c.n = n; 263 | for(int i = 0; i < n; ++i) { 264 | c.p[i] = p[i]; 265 | } 266 | if(n <= 2) { 267 | return ; 268 | } 269 | 270 | int &top = c.n; 271 | top = 1; 272 | for ( int i = 2 ; i < n ; i ++ ) { 273 | while ( top && threeValue(( c.p[top] - p[i] ).X( c.p[top - 1] - p[i] )) >= 0 ) 274 | top --; 275 | c.p[++top] = p[i]; 276 | } 277 | int temp = top; 278 | c.p[++ top] = p[n - 2]; 279 | for ( int i = n - 3 ; i >= 0 ; i -- ) { 280 | while ( top != temp && threeValue(( c.p[top] - p[i] ).X( c.p[top - 1] - p[i] )) >= 0 ) 281 | top --; 282 | c.p[++ top] = p[i]; 283 | } 284 | } 285 | 286 | // 是否凸多边形 287 | bool Polygon::isConvex() { 288 | bool s[3] = { false , false , false }; 289 | p[n] = p[0], p[n + 1] = p[1]; 290 | for ( int i = 0 ; i < n ; i ++ ) { 291 | s[threeValue(( p[i + 1] - p[i] ) * ( p[i + 2] - p[i] )) + 1] = true; 292 | // 叉乘有左有右,肯定是凹的 293 | if ( s[0] && s[2] ) return false; 294 | } 295 | return true; 296 | } 297 | 298 | // 点是否在凸多边形内 299 | bool Polygon::isPointInConvex(const Point2D &P) { 300 | bool s[3] = { false , false , false }; 301 | p[n] = p[0]; 302 | for ( int i = 0 ; i < n ; i ++ ) { 303 | s[threeValue(( p[i + 1] - P ) * ( p[i] - P )) + 1] = true; 304 | if ( s[0] && s[2] ) return false; 305 | if ( s[1] ) return true; 306 | } 307 | return true; 308 | } 309 | 310 | // 转成逆时针顺序 311 | void Polygon::convertToCounterClockwise() { 312 | if(area() >= 0) { 313 | return ; 314 | } 315 | for(int i = 1; i <= n / 2; ++i) { 316 | Point2D tmp = p[i]; 317 | p[i] = p[n-i]; 318 | p[n-i] = tmp; 319 | } 320 | } 321 | 322 | Point2D Polygon::CalcBary() { 323 | Point2D ret(0, 0); 324 | double area = 0; 325 | p[n] = p[0]; 326 | for ( int i = 0 ; i < n ; i ++ ) { 327 | double temp = p[i] * p[i + 1]; 328 | if ( threeValue(temp) == 0 ) continue; 329 | area += temp; 330 | ret = ret + ( p[i] + p[i + 1] ) * ( temp / 3 ); 331 | } 332 | return ret / area; 333 | } 334 | 335 | // 点对 336 | struct Point2D_Pair { 337 | Point2D a, b; 338 | Point2D_Pair() {} 339 | Point2D_Pair(Point2D _a, Point2D _b): a(_a), b(_b) { 340 | } 341 | Point2D center(); 342 | Vector2D direction(); 343 | double len(); 344 | void print(); 345 | }; 346 | 347 | Point2D Point2D_Pair::center() { 348 | return (a + b) / 2; 349 | } 350 | 351 | Vector2D Point2D_Pair::direction() { 352 | return b - a; 353 | } 354 | 355 | double Point2D_Pair::len() { 356 | return direction().len(); 357 | } 358 | 359 | void Point2D_Pair::print() { 360 | printf("点对如下:\n"); 361 | a.print(); 362 | b.print(); 363 | } 364 | 365 | class Circle { 366 | Point2D center; 367 | double radius; 368 | public: 369 | Circle() {} 370 | Circle(Point2D c, double r): center(c), radius(r) { 371 | } 372 | 373 | double getOriginFanArea(double angle); 374 | double getOriginTriangleArea(Point2D A, Point2D B); 375 | double intersectWithPolygon(Polygon &poly); 376 | 377 | static int getCenterByTwoPoints(Point2D_Pair p, double r, Point2D_Pair& ret); 378 | static int getCenterByAngle(Point2D o, Point2D a, Point2D b, double r, Point2D& ret); 379 | }; 380 | 381 | // 给定两个点和一个半径r,求经过这两点的圆的圆心。 382 | // 返回值:圆心数量 (0/1/2) 383 | int Circle::getCenterByTwoPoints(Point2D_Pair p, double r, Point2D_Pair& ret) { 384 | double chordal = p.len(); 385 | int rc = threeValue(r - chordal/2); 386 | if(rc == -1) { 387 | // 1.半径小于弦长一半,无解 388 | return 0; 389 | }else if(rc == 0) { 390 | // 2.半径等于弦长一半,圆心唯一,为弦中点 391 | ret.a = ret.b = p.center(); 392 | return 1; 393 | }else { 394 | // 3.半径大于弦长一半,则半径为斜边,弦长一半为直角边,可获得两个圆心 395 | double verLen = sqrt(r*r - chordal*chordal/4); 396 | Point2D ip = p.direction(); 397 | ip.normalize(); 398 | ret.a = p.center() + ip.turnLeft()*verLen; 399 | ret.b = p.center() + ip.turnRight()*verLen; 400 | return 2; 401 | } 402 | } 403 | 404 | // 给定oa-ob这段角度,求卡在这个角内的圆的圆心 405 | // 注意:请保证ob在oa的逆时针方向,且|oa| != |ob| 406 | // 返回值:圆心数量 (0/1) 407 | int Circle::getCenterByAngle(Point2D o, Point2D a, Point2D b, double r, Point2D& ret) { 408 | Vector2D OA = a - o; 409 | Vector2D OB = b - o; 410 | double ad = OA.angle(); 411 | double bd = OB.angle(); 412 | if(bd < ad) { 413 | bd += 2*PI; 414 | } 415 | // 两射线构成的角 >= 180度,则无法放入圆 416 | if( threeValue(bd - ad - PI) >= 0 ) { 417 | return 0; 418 | } 419 | OA.normalize(), OB.normalize(); 420 | ret = o + (OA - OB).normalize().turnLeft() * r; 421 | return 1; 422 | } 423 | 424 | double Circle::getOriginFanArea(double angle) { 425 | return (angle/2)*radius*radius; 426 | } 427 | 428 | double Circle::getOriginTriangleArea(Point2D A, Point2D B) { 429 | Vector2D OA = A - center; 430 | Vector2D OB = B - center; 431 | int sign = threeValue(OA.X(OB)); 432 | double lenA = OA.len(); 433 | double lenB = OB.len(); 434 | double angleAOB = acos(OA * OB / lenA / lenB); 435 | 436 | if(!sign) { 437 | // 三角形退化为直线 438 | return 0; 439 | } 440 | 441 | Vector2D OH = (B-A).turnLeft(); 442 | line2DTriple lt(A, B); 443 | double H = lt.getPointDist(center); 444 | 445 | // 情况1:圆心到第三条边(不过圆心那条边)距离大于等于半径。 446 | if(threeValue(H-radius) >= 0) { 447 | return sign*getOriginFanArea(angleAOB); 448 | } 449 | 450 | int lenACmpR = threeValue(lenA - radius); 451 | int lenBCmpR = threeValue(lenB - radius); 452 | // 情况2:圆心到第三条边距离小于半径R 453 | 454 | // 2.a:OA和OB都小于等于R 455 | if( lenACmpR <= 0 && lenBCmpR <= 0) { 456 | return OA.X(OB) / 2; 457 | } 458 | // 2.bc:OA和OB都大于等于R 459 | if( lenACmpR >= 0 && lenBCmpR >= 0) { 460 | if(OH.sameSide(OA, OB)) { 461 | // 同边,扇形 462 | return sign*getOriginFanArea(angleAOB); 463 | }else { 464 | // 两边,扇形相减再补上一个三角形 465 | double angleCOD = 2*acos(H / radius); 466 | double fanArea = getOriginFanArea(angleAOB-angleCOD); 467 | double triangleArea = H*radius*sin(angleCOD/2); 468 | return sign*(fanArea + triangleArea); 469 | } 470 | } 471 | // 2.d:OA和OB 一条大于R,一条小于等于R 472 | // 让A成为小的那一条 473 | if(lenA > lenB) { 474 | Point2D tmp = A; A = B; B = tmp; 475 | OA = A - center; lenA = OA.len(); 476 | OB = B - center; lenB = OB.len(); 477 | } 478 | double lenAB = (B-A).len(); 479 | // 余弦定理 480 | double angleBAO = acos( (lenAB*lenAB+lenA*lenA-lenB*lenB) / 2 / lenAB / lenA ); 481 | // 正弦定理 482 | double angleACO = asin( sin(angleBAO)/radius*lenA ); 483 | // 三角形内角和 484 | double angleAOC = PI - angleBAO - angleACO; 485 | 486 | return sign*(getOriginFanArea(angleAOB - angleAOC) + 1/2.0*sin(angleAOC)*radius*lenA); 487 | } 488 | 489 | double Circle::intersectWithPolygon(Polygon &poly) { 490 | // 1.多边形转换成逆时针 491 | poly.convertToCounterClockwise(); 492 | 493 | // 2.面积计算 494 | double sum = 0; 495 | for(int i = 0; i < poly.n; ++i) { 496 | sum += getOriginTriangleArea(poly.p[i], poly.p[i+1]); 497 | } 498 | return fabs(sum); 499 | } 500 | -------------------------------------------------------------------------------- /计算几何/计算几何 圆相关 模板.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | const int MAXP = 1100; 8 | #define PI acos(-1.0) 9 | #define eps 1e-15 10 | #define LL __int64 11 | typedef double Type; 12 | 13 | // 三值函数 14 | int threeValue(Type d) { 15 | if(fabs(d) < 1e-6) 16 | return 0; 17 | return d > 0 ? 1 : -1; 18 | } 19 | 20 | // 两线段交点类型 21 | enum SegCrossType { 22 | SCT_NONE = 0, 23 | SCT_CROSS = 1, // 正常相交 24 | SCT_ENDPOINT_ON = 2, // 其中一条线段的端点在另一条上 25 | }; 26 | 27 | class Point2D { 28 | Type x, y; 29 | 30 | public: 31 | Point2D(){ 32 | } 33 | Point2D(Type _x, Type _y): x(_x), y(_y) {} 34 | void read() { 35 | scanf("%lf %lf", &x, &y); 36 | } 37 | void print() { 38 | printf("<%lf, %lf>\n", x, y); 39 | } 40 | Point2D turnLeft(); 41 | Point2D turnRight(); 42 | double angle(); 43 | Point2D operator+(const Point2D& other) const; 44 | Point2D operator-(const Point2D& other) const; 45 | Point2D operator*(const double &k) const; 46 | Point2D operator/(const double &k) const; 47 | Type operator*(const Point2D& other) const; 48 | bool operator <(const Point2D &p) const; 49 | Type X(const Point2D& other); 50 | double len(); 51 | Point2D normalize(); 52 | }; 53 | 54 | typedef Point2D Vector2D; 55 | 56 | double Vector2D::len() { 57 | return sqrt(x*x + y*y); 58 | } 59 | 60 | Point2D Vector2D::normalize() { 61 | double l = len(); 62 | if(threeValue(l)) { 63 | x /= l; 64 | y /= l; 65 | } 66 | return *this; 67 | } 68 | 69 | Point2D Point2D::turnLeft() { 70 | return Point2D(-y, x); 71 | } 72 | Point2D Point2D::turnRight() { 73 | return Point2D(y, -x); 74 | } 75 | double Point2D::angle() { 76 | return atan2(y, x); 77 | } 78 | 79 | Point2D Point2D::operator+(const Point2D& other) const { 80 | return Point2D(x + other.x, y + other.y); 81 | } 82 | 83 | Point2D Point2D::operator-(const Point2D& other) const { 84 | return Point2D(x - other.x, y - other.y); 85 | } 86 | 87 | Point2D Point2D::operator *(const double &k) const { 88 | return Point2D(x * k, y * k); 89 | } 90 | 91 | Point2D Point2D::operator /(const double &k) const { 92 | return Point2D(x / k, y / k); 93 | } 94 | 95 | bool Point2D::operator <(const Point2D &p) const { 96 | return y + eps < p.y || ( y < p.y + eps && x + eps < p.x ); 97 | } 98 | 99 | // !!!!注意!!!! 100 | // 如果Type为int,则乘法可能导致int32溢出,小心谨慎 101 | // 点乘 102 | Type Point2D::operator*(const Point2D& other) const { 103 | return x*other.x + y*other.y; 104 | } 105 | // 叉乘 106 | Type Point2D::X(const Point2D& other) { 107 | return x*other.y - y*other.x; 108 | } 109 | 110 | class Segment2D { 111 | Point2D s, t; 112 | public: 113 | void read() { 114 | s.read(); 115 | t.read(); 116 | } 117 | 118 | // 定点叉乘 119 | // 外部找一点p,然后计算 (p-s)×(t-s) 120 | Type cross(const Point2D& p) const { 121 | return (p - s).X(t - s); 122 | } 123 | 124 | // 跨立测验 125 | // 将当前线段作为一条很长的直线,检测线段other是否跨立在这条直线的两边 126 | bool lineCross(const Segment2D& other) const; 127 | 128 | // 点是否在线段上 129 | bool pointOn(const Point2D& p) const; 130 | 131 | // 线段判交 132 | // 1.通过跨立测验 133 | // 2.点是否在线段上 134 | SegCrossType segCross(const Segment2D& other); 135 | }; 136 | 137 | bool Segment2D::lineCross(const Segment2D& other) const { 138 | return threeValue(cross(other.s)) * threeValue(cross(other.t)) == -1; 139 | } 140 | 141 | bool Segment2D::pointOn(const Point2D& p) const { 142 | // 满足两个条件: 143 | // 1.叉乘为0, (p-s)×(t-s) == 0 144 | // 2.点乘为-1或0,(p-s)*(p-t) <= 0 145 | return cross(p) == 0 && (p-s)*(p-t) <= 0; 146 | } 147 | 148 | SegCrossType Segment2D::segCross(const Segment2D& other) { 149 | if(this->lineCross(other) && other.lineCross(*this)) { 150 | // 两次跨立都成立,则必然相交与一点 151 | return SCT_CROSS; 152 | } 153 | // 任意一条线段的某个端点是否在其中一条线段上,四种情况 154 | if(pointOn(other.s) || pointOn(other.t) || 155 | other.pointOn(s) || other.pointOn(t) ) { 156 | return SCT_ENDPOINT_ON; 157 | } 158 | return SCT_NONE; 159 | } 160 | 161 | class Line2D { 162 | public: 163 | Point2D a, b; 164 | Line2D() {} 165 | Line2D(const Point2D& _a, const Point2D& _b): a(_a), b(_b) {} 166 | Point2D getCrossPoint(const Line2D& ); 167 | bool isParallelTo(const Line2D& ); 168 | }; 169 | 170 | // 两条不平行的直线必有交点 171 | // 利用叉乘求面积法的相似三角形比值得出交点 172 | Point2D Line2D::getCrossPoint(const Line2D& other) { 173 | double SA = (other.a - a).X(b - a); 174 | double SB = (b - a).X(other.b - a); 175 | return (other.b * SA + other.a * SB) / (SA + SB); 176 | } 177 | 178 | bool Line2D::isParallelTo(const Line2D& other) { 179 | return !threeValue( (b-a).X(other.b - other.a) ); 180 | } 181 | 182 | struct Polygon { 183 | int n; 184 | Point2D p[MAXP]; 185 | 186 | void print(); 187 | double area(); 188 | void getConvex(Polygon &c); 189 | bool isConvex(); 190 | bool isPointInConvex(const Point2D &P); 191 | Point2D CalcBary(); 192 | void convertToCounterClockwise(); 193 | bool 194 | }; 195 | 196 | void Polygon::print() { 197 | int i; 198 | printf("%d\n", n); 199 | for(i = 0; i < n; ++i) { 200 | p[i].print(); 201 | } 202 | } 203 | 204 | double Polygon::area() { 205 | double sum = 0; 206 | p[n] = p[0]; 207 | for ( int i = 0 ; i < n; i ++ ) 208 | sum += p[i].X(p[i + 1]); 209 | return sum / 2; 210 | } 211 | 212 | // 求凸包 213 | void Polygon::getConvex(Polygon &c) { 214 | sort(p, p + n); 215 | c.n = n; 216 | for(int i = 0; i < n; ++i) { 217 | c.p[i] = p[i]; 218 | } 219 | if(n <= 2) { 220 | return ; 221 | } 222 | 223 | int &top = c.n; 224 | top = 1; 225 | for ( int i = 2 ; i < n ; i ++ ) { 226 | while ( top && threeValue(( c.p[top] - p[i] ).X( c.p[top - 1] - p[i] )) >= 0 ) 227 | top --; 228 | c.p[++top] = p[i]; 229 | } 230 | int temp = top; 231 | c.p[++ top] = p[n - 2]; 232 | for ( int i = n - 3 ; i >= 0 ; i -- ) { 233 | while ( top != temp && threeValue(( c.p[top] - p[i] ).X( c.p[top - 1] - p[i] )) >= 0 ) 234 | top --; 235 | c.p[++ top] = p[i]; 236 | } 237 | } 238 | 239 | // 是否凸多边形 240 | bool Polygon::isConvex() { 241 | bool s[3] = { false , false , false }; 242 | p[n] = p[0], p[n + 1] = p[1]; 243 | for ( int i = 0 ; i < n ; i ++ ) { 244 | s[threeValue(( p[i + 1] - p[i] ) * ( p[i + 2] - p[i] )) + 1] = true; 245 | // 叉乘有左有右,肯定是凹的 246 | if ( s[0] && s[2] ) return false; 247 | } 248 | return true; 249 | } 250 | 251 | // 点是否在凸多边形内 252 | bool Polygon::isPointInConvex(const Point2D &P) { 253 | bool s[3] = { false , false , false }; 254 | p[n] = p[0]; 255 | for ( int i = 0 ; i < n ; i ++ ) { 256 | s[threeValue(( p[i + 1] - P ) * ( p[i] - P )) + 1] = true; 257 | if ( s[0] && s[2] ) return false; 258 | if ( s[1] ) return true; 259 | } 260 | return true; 261 | } 262 | 263 | // 转成逆时针顺序 264 | void Polygon::convertToCounterClockwise() { 265 | if(area() >= 0) { 266 | return ; 267 | } 268 | for(int i = 1; i <= n / 2; ++i) { 269 | Point2D tmp = p[i]; 270 | p[i] = p[n-i]; 271 | p[n-i] = tmp; 272 | } 273 | } 274 | 275 | Point2D Polygon::CalcBary() { 276 | Point2D ret(0, 0); 277 | double area = 0; 278 | p[n] = p[0]; 279 | for ( int i = 0 ; i < n ; i ++ ) { 280 | double temp = p[i] * p[i + 1]; 281 | if ( threeValue(temp) == 0 ) continue; 282 | area += temp; 283 | ret = ret + ( p[i] + p[i + 1] ) * ( temp / 3 ); 284 | } 285 | return ret / area; 286 | } 287 | 288 | // 点对 289 | struct Point2D_Pair { 290 | Point2D a, b; 291 | Point2D_Pair() {} 292 | Point2D_Pair(Point2D _a, Point2D _b): a(_a), b(_b) { 293 | } 294 | Point2D center(); 295 | Vector2D direction(); 296 | double len(); 297 | void print(); 298 | }; 299 | 300 | Point2D Point2D_Pair::center() { 301 | return (a + b) / 2; 302 | } 303 | 304 | Vector2D Point2D_Pair::direction() { 305 | return b - a; 306 | } 307 | 308 | double Point2D_Pair::len() { 309 | return direction().len(); 310 | } 311 | 312 | void Point2D_Pair::print() { 313 | printf("点对如下:\n"); 314 | a.print(); 315 | b.print(); 316 | } 317 | 318 | class Circle { 319 | Point2D center; 320 | double radius; 321 | public: 322 | Circle() {} 323 | Circle(Point2D c, double r): center(c), radius(r) { 324 | } 325 | 326 | static int getCenterByTwoPoints(Point2D_Pair p, double r, Point2D_Pair& ret); 327 | static int getCenterByAngle(Point2D o, Point2D a, Point2D b, double r, Point2D& ret); 328 | }; 329 | 330 | // 给定两个点和一个半径r,求经过这两点的圆的圆心。 331 | // 返回值:圆心数量 (0/1/2) 332 | int Circle::getCenterByTwoPoints(Point2D_Pair p, double r, Point2D_Pair& ret) { 333 | double chordal = p.len(); 334 | int rc = threeValue(r - chordal/2); 335 | if(rc == -1) { 336 | // 1.半径小于弦长一半,无解 337 | return 0; 338 | }else if(rc == 0) { 339 | // 2.半径等于弦长一半,圆心唯一,为弦中点 340 | ret.a = ret.b = p.center(); 341 | return 1; 342 | }else { 343 | // 3.半径大于弦长一半,则半径为斜边,弦长一半为直角边,可获得两个圆心 344 | double verLen = sqrt(r*r - chordal*chordal/4); 345 | Point2D ip = p.direction(); 346 | ip.normalize(); 347 | ret.a = p.center() + ip.turnLeft()*verLen; 348 | ret.b = p.center() + ip.turnRight()*verLen; 349 | return 2; 350 | } 351 | } 352 | 353 | // 给定oa-ob这段角度,求卡在这个角内的圆的圆心 354 | // 注意:请保证ob在oa的逆时针方向,且|oa| != |ob| 355 | // 返回值:圆心数量 (0/1) 356 | int Circle::getCenterByAngle(Point2D o, Point2D a, Point2D b, double r, Point2D& ret) { 357 | Vector2D OA = a - o; 358 | Vector2D OB = b - o; 359 | double ad = OA.angle(); 360 | double bd = OB.angle(); 361 | if(bd < ad) { 362 | bd += 2*PI; 363 | } 364 | // 两射线构成的角 >= 180度,则无法放入圆 365 | if( threeValue(bd - ad - PI) >= 0 ) { 366 | return 0; 367 | } 368 | OA.normalize(), OB.normalize(); 369 | ret = o + (OA - OB).normalize().turnLeft() * r; 370 | return 1; 371 | } 372 | 373 | -------------------------------------------------------------------------------- /计算几何/计算几何 最大空凸包.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/计算几何/计算几何 最大空凸包.cpp -------------------------------------------------------------------------------- /计算几何/计算几何 最小包围球 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/计算几何/计算几何 最小包围球 模板.cpp -------------------------------------------------------------------------------- /计算几何/计算几何 最小覆盖圆 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/计算几何/计算几何 最小覆盖圆 模板.cpp -------------------------------------------------------------------------------- /计算几何/计算几何2D模板.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | const int MAXP = 1100; 8 | #define eps 1e-6 9 | #define LL __int64 10 | typedef double Type; 11 | 12 | class HalfPlane; 13 | class Polygon; 14 | 15 | // 三值函数 16 | int threeValue(Type d) { 17 | if(fabs(d) < 1e-6) 18 | return 0; 19 | return d > 0 ? 1 : -1; 20 | } 21 | 22 | // 两线段交点类型 23 | enum SegCrossType { 24 | SCT_NONE = 0, 25 | SCT_CROSS = 1, // 正常相交 26 | SCT_ENDPOINT_ON = 2, // 其中一条线段的端点在另一条上 27 | }; 28 | 29 | class Point2D { 30 | Type x, y; 31 | 32 | public: 33 | Point2D(){ 34 | } 35 | Point2D(Type _x, Type _y): x(_x), y(_y) {} 36 | void read() { 37 | scanf("%lf %lf", &x, &y); 38 | } 39 | void print() { 40 | printf("<%lf, %lf>\n", x, y); 41 | } 42 | Point2D turnLeft(); 43 | Point2D turnRight(); 44 | double angle(); 45 | Point2D operator+(const Point2D& other) const; 46 | Point2D operator-(const Point2D& other) const; 47 | Point2D operator*(const double &k) const; 48 | Point2D operator/(const double &k) const; 49 | Type operator*(const Point2D& other) const; 50 | bool operator <(const Point2D &p) const; 51 | Type X(const Point2D& other); 52 | double len(); 53 | void normalize(); 54 | }; 55 | 56 | typedef Point2D Vector2D; 57 | 58 | double Vector2D::len() { 59 | return sqrt(x*x + y*y); 60 | } 61 | 62 | void Vector2D::normalize() { 63 | double l = len(); 64 | if(threeValue(l)) { 65 | x /= l; 66 | y /= l; 67 | } 68 | } 69 | 70 | Point2D Point2D::turnLeft() { 71 | return Point2D(-y, x); 72 | } 73 | Point2D Point2D::turnRight() { 74 | return Point2D(y, -x); 75 | } 76 | double Point2D::angle() { 77 | return atan2(y, x); 78 | } 79 | 80 | Point2D Point2D::operator+(const Point2D& other) const { 81 | return Point2D(x + other.x, y + other.y); 82 | } 83 | 84 | Point2D Point2D::operator-(const Point2D& other) const { 85 | return Point2D(x - other.x, y - other.y); 86 | } 87 | 88 | Point2D Point2D::operator *(const double &k) const { 89 | return Point2D(x * k, y * k); 90 | } 91 | 92 | Point2D Point2D::operator /(const double &k) const { 93 | return Point2D(x / k, y / k); 94 | } 95 | 96 | bool Point2D::operator <(const Point2D &p) const { 97 | return y + eps < p.y || ( y < p.y + eps && x + eps < p.x ); 98 | } 99 | 100 | // !!!!注意!!!! 101 | // 如果Type为int,则乘法可能导致int32溢出,小心谨慎 102 | // 点乘 103 | Type Point2D::operator*(const Point2D& other) const { 104 | return x*other.x + y*other.y; 105 | } 106 | // 叉乘 107 | Type Point2D::X(const Point2D& other) { 108 | return x*other.y - y*other.x; 109 | } 110 | 111 | class Segment2D { 112 | Point2D s, t; 113 | public: 114 | void read() { 115 | s.read(); 116 | t.read(); 117 | } 118 | 119 | // 定点叉乘 120 | // 外部找一点p,然后计算 (p-s)×(t-s) 121 | Type cross(const Point2D& p) const { 122 | return (p - s).X(t - s); 123 | } 124 | 125 | // 跨立测验 126 | // 将当前线段作为一条很长的直线,检测线段other是否跨立在这条直线的两边 127 | bool lineCross(const Segment2D& other) const; 128 | 129 | // 点是否在线段上 130 | bool pointOn(const Point2D& p) const; 131 | 132 | // 线段判交 133 | // 1.通过跨立测验 134 | // 2.点是否在线段上 135 | SegCrossType segCross(const Segment2D& other); 136 | }; 137 | 138 | bool Segment2D::lineCross(const Segment2D& other) const { 139 | return threeValue(cross(other.s)) * threeValue(cross(other.t)) == -1; 140 | } 141 | 142 | bool Segment2D::pointOn(const Point2D& p) const { 143 | // 满足两个条件: 144 | // 1.叉乘为0, (p-s)×(t-s) == 0 145 | // 2.点乘为-1或0,(p-s)*(p-t) <= 0 146 | return threeValue(cross(p)) == 0 && (p-s)*(p-t) <= 0; 147 | } 148 | 149 | SegCrossType Segment2D::segCross(const Segment2D& other) { 150 | if(this->lineCross(other) && other.lineCross(*this)) { 151 | // 两次跨立都成立,则必然相交与一点 152 | return SCT_CROSS; 153 | } 154 | // 任意一条线段的某个端点是否在其中一条线段上,四种情况 155 | if(pointOn(other.s) || pointOn(other.t) || 156 | other.pointOn(s) || other.pointOn(t) ) { 157 | return SCT_ENDPOINT_ON; 158 | } 159 | return SCT_NONE; 160 | } 161 | 162 | class Line2D { 163 | public: 164 | Point2D a, b; 165 | Line2D() {} 166 | Line2D(const Point2D& _a, const Point2D& _b): a(_a), b(_b) {} 167 | Point2D getCrossPoint(const Line2D& ); 168 | bool isParallelTo(const Line2D& ); 169 | }; 170 | 171 | // 两条不平行的直线必有交点 172 | // 利用叉乘求面积法的相似三角形比值得出交点 173 | Point2D Line2D::getCrossPoint(const Line2D& other) { 174 | double SA = (other.a - a).X(b - a); 175 | double SB = (b - a).X(other.b - a); 176 | return (other.b * SA + other.a * SB) / (SA + SB); 177 | } 178 | 179 | bool Line2D::isParallelTo(const Line2D& other) { 180 | return !threeValue( (b-a).X(other.b - other.a) ); 181 | } 182 | 183 | /* 半平面定义: 184 | 沿着射线(a->b)方向的左手面定义为半平面 185 | 所有的多边形建立的时候,需要注意,保证点按照逆时针排列 186 | 判断是否逆时针排列可以用面积 >0 判定 187 | */ 188 | class HalfPlane : public Line2D { 189 | double angle; 190 | public: 191 | HalfPlane() {} 192 | HalfPlane(const Point2D &_a, const Point2D& _b) { 193 | a = _a; 194 | b = _b; 195 | angle = (_b - _a).angle(); 196 | } 197 | bool equalAngle(const HalfPlane &other) const; 198 | bool operator < (const HalfPlane &other) const; 199 | Type X(const Point2D &p) const; 200 | bool isPointIn(const Point2D &p) const; 201 | void move(double dist); 202 | }; 203 | 204 | class HalfPlanes { 205 | int n; 206 | HalfPlane hp[MAXP]; 207 | void unique(); 208 | 209 | Point2D p[MAXP]; 210 | int que[MAXP]; 211 | int head, tail; 212 | 213 | void print(); 214 | public: 215 | HalfPlanes() {} 216 | ~HalfPlanes() {} 217 | void init(); 218 | int size() {return n;} 219 | void getHalfPlane(HalfPlanes& H); 220 | void addHalfPlane(const HalfPlane &); 221 | void addRectBorder(Type lx, Type ly, Type rx, Type ry); 222 | bool doIntersection(); 223 | void getConvex(Polygon &convex); 224 | 225 | static HalfPlanes &Instance() { 226 | static HalfPlanes inst; 227 | return inst; 228 | } 229 | }; 230 | 231 | struct Polygon { 232 | int n; 233 | Point2D p[MAXP]; 234 | 235 | void print(); 236 | double area(); 237 | void getConvex(Polygon &c); 238 | bool isConvex(); 239 | bool isPointInConvex(const Point2D &P); 240 | Point2D CalcBary(); 241 | double getPolygonIntersect(Polygon& other); 242 | void convertToCounterClockwise(); 243 | int constructTriangleHalfPlane(const Point2D &A, const Point2D &B, const Point2D &C, HalfPlane* hp); 244 | }; 245 | 246 | void Polygon::print() { 247 | int i; 248 | printf("%d\n", n); 249 | for(i = 0; i < n; ++i) { 250 | p[i].print(); 251 | } 252 | } 253 | 254 | double Polygon::area() { 255 | double sum = 0; 256 | p[n] = p[0]; 257 | for ( int i = 0 ; i < n; i ++ ) 258 | sum += p[i].X(p[i + 1]); 259 | return sum / 2; 260 | } 261 | 262 | // 求凸包 263 | void Polygon::getConvex(Polygon &c) { 264 | sort(p, p + n); 265 | c.n = n; 266 | for(int i = 0; i < n; ++i) { 267 | c.p[i] = p[i]; 268 | } 269 | if(n <= 2) { 270 | return ; 271 | } 272 | 273 | int &top = c.n; 274 | top = 1; 275 | for ( int i = 2 ; i < n ; i ++ ) { 276 | while ( top && threeValue(( c.p[top] - p[i] ).X( c.p[top - 1] - p[i] )) >= 0 ) 277 | top --; 278 | c.p[++top] = p[i]; 279 | } 280 | int temp = top; 281 | c.p[++ top] = p[n - 2]; 282 | for ( int i = n - 3 ; i >= 0 ; i -- ) { 283 | while ( top != temp && threeValue(( c.p[top] - p[i] ).X( c.p[top - 1] - p[i] )) >= 0 ) 284 | top --; 285 | c.p[++ top] = p[i]; 286 | } 287 | } 288 | 289 | // 是否凸多边形 290 | bool Polygon::isConvex() { 291 | bool s[3] = { false , false , false }; 292 | p[n] = p[0], p[n + 1] = p[1]; 293 | for ( int i = 0 ; i < n ; i ++ ) { 294 | s[threeValue(( p[i + 1] - p[i] ) * ( p[i + 2] - p[i] )) + 1] = true; 295 | // 叉乘有左有右,肯定是凹的 296 | if ( s[0] && s[2] ) return false; 297 | } 298 | return true; 299 | } 300 | 301 | // 点是否在凸多边形内 302 | bool Polygon::isPointInConvex(const Point2D &P) { 303 | bool s[3] = { false , false , false }; 304 | p[n] = p[0]; 305 | for ( int i = 0 ; i < n ; i ++ ) { 306 | s[threeValue(( p[i + 1] - P ) * ( p[i] - P )) + 1] = true; 307 | if ( s[0] && s[2] ) return false; 308 | if ( s[1] ) return true; 309 | } 310 | return true; 311 | } 312 | 313 | // 转成逆时针顺序 314 | void Polygon::convertToCounterClockwise() { 315 | if(area() >= 0) { 316 | return ; 317 | } 318 | for(int i = 1; i <= n / 2; ++i) { 319 | Point2D tmp = p[i]; 320 | p[i] = p[n-i]; 321 | p[n-i] = tmp; 322 | } 323 | } 324 | 325 | // 求两任意多边形的交 326 | // 要求两个多边形逆时针排列 327 | double Polygon::getPolygonIntersect(Polygon& other) { 328 | int i, j; 329 | HalfPlane hp[2][3]; 330 | Polygon g; 331 | 332 | convertToCounterClockwise(); 333 | other.convertToCounterClockwise(); 334 | 335 | double area = 0; 336 | // 枚举每个三角形,记得正负 337 | for(i = 0; i < n; ++i) { 338 | Point2D O(0, 0); 339 | // 两个多边形分别拆成两个有向三角形,求半平面交,再累加 340 | int td = constructTriangleHalfPlane(O, p[i], p[i+1], hp[0]); 341 | if(td == 0) 342 | continue; 343 | 344 | for(j = 0; j < other.n; ++j) { 345 | HalfPlanes &h = HalfPlanes::Instance(); 346 | h.init(); 347 | int flag = td * constructTriangleHalfPlane(O, other.p[j], other.p[j+1], hp[1]); 348 | if(flag) { 349 | h.addHalfPlane(hp[0][0]), h.addHalfPlane(hp[0][1]), h.addHalfPlane(hp[0][2]); 350 | h.addHalfPlane(hp[1][0]), h.addHalfPlane(hp[1][1]), h.addHalfPlane(hp[1][2]); 351 | 352 | if(h.doIntersection()) { 353 | h.getConvex(g); 354 | if( threeValue(g.area()) ) { 355 | area += flag * g.area(); 356 | } 357 | } 358 | } 359 | } 360 | } 361 | // 注意!!!!这里求出来的相交 面积允许为负数 362 | return area; 363 | } 364 | 365 | int Polygon::constructTriangleHalfPlane(const Point2D &A, const Point2D &B, const Point2D &C, HalfPlane* hp) { 366 | int v = threeValue((B-A).X(C-A)); 367 | if(v == 0) return 0; 368 | if(v < 0) { 369 | hp[0] = HalfPlane(A, C); 370 | hp[1] = HalfPlane(C, B); 371 | hp[2] = HalfPlane(B, A); 372 | return -1; 373 | }else { 374 | hp[0] = HalfPlane(A, B); 375 | hp[1] = HalfPlane(B, C); 376 | hp[2] = HalfPlane(C, A); 377 | return 1; 378 | } 379 | } 380 | 381 | 382 | Point2D Polygon::CalcBary() { 383 | Point2D ret(0, 0); 384 | double area = 0; 385 | p[n] = p[0]; 386 | for ( int i = 0 ; i < n ; i ++ ) { 387 | double temp = p[i] * p[i + 1]; 388 | if ( threeValue(temp) == 0 ) continue; 389 | area += temp; 390 | ret = ret + ( p[i] + p[i + 1] ) * ( temp / 3 ); 391 | } 392 | return ret / area; 393 | } 394 | 395 | 396 | bool HalfPlane::equalAngle(const HalfPlane &other) const { 397 | return !threeValue(angle - other.angle); 398 | } 399 | 400 | // 极角不同则按照极角从小到大排序 401 | // 如果极角相同,则进行如下操作: 402 | // 向量A = (b - a) 叉乘 向量 B = (other.a - a) 403 | // 如果大于0,说明向量A在向量B的右侧,保留A,剔除B; 404 | bool HalfPlane::operator < (const HalfPlane &other) const { 405 | if( threeValue(angle - other.angle) ) { 406 | return angle < other.angle; 407 | } 408 | return !isPointIn(other.a); 409 | } 410 | 411 | // 这个函数非常有用 用于isPointIn的判断 412 | // 叉乘结果 <= 0,则说明p点在半平面区域内 413 | Type HalfPlane::X(const Point2D &p) const { 414 | return ( b - a ).X( p - a ); 415 | } 416 | 417 | bool HalfPlane::isPointIn(const Point2D &p) const { 418 | return threeValue( X(p) ) >= 0; 419 | } 420 | 421 | // 半平面靠着左方进行缩进,缩进距离为dist 422 | void HalfPlane::move(double dist) { 423 | Point2D t = (b-a).turnLeft(); 424 | t.normalize(); 425 | a = a + t * dist; 426 | b = b + t * dist; 427 | } 428 | 429 | void HalfPlanes::print() { 430 | for(int i = 0; i < n; ++i) { 431 | printf("<%d>\n", i); 432 | hp[i].a.print(); 433 | hp[i].b.print(); 434 | } 435 | } 436 | 437 | void HalfPlanes::init() { 438 | n = 0; 439 | } 440 | 441 | void HalfPlanes::addHalfPlane(const HalfPlane & h) { 442 | hp[n++] = h; 443 | } 444 | 445 | void HalfPlanes::addRectBorder(Type lx, Type ly, Type rx, Type ry) { 446 | addHalfPlane( HalfPlane(Point2D(lx, ly), Point2D(rx, ly) )); 447 | addHalfPlane( HalfPlane(Point2D(rx, ly), Point2D(rx, ry) )); 448 | addHalfPlane( HalfPlane(Point2D(rx, ry), Point2D(lx, ry) )); 449 | addHalfPlane( HalfPlane(Point2D(lx, ry), Point2D(lx, ly) )); 450 | } 451 | 452 | void HalfPlanes::getHalfPlane(HalfPlanes& H) { 453 | for(int i = 0; i < H.size(); ++i) { 454 | addHalfPlane(H.hp[i]); 455 | } 456 | } 457 | void HalfPlanes::unique() { 458 | int m = 1; 459 | for(int i = 1; i < n; ++i) { 460 | // 极角相同取其前 461 | if( !hp[i].equalAngle(hp[i-1]) ) { 462 | hp[m++] = hp[i]; 463 | } 464 | } 465 | n = m; 466 | } 467 | 468 | bool HalfPlanes::doIntersection() { 469 | // 1.按照极角排序,剔除极角相同的半平面 470 | sort(hp, hp + n); 471 | unique(); 472 | //print(); 473 | // 2.将前两个半平面放入单调队列,并且计算出交点 474 | que[ head=0 ] = 0, que[ tail=1 ] = 1; 475 | p[1] = hp[0].getCrossPoint(hp[1]); 476 | // 3.按照极角顺序线性枚举所有平面,和队列中的半平面进行求交运算 477 | for(int i = 2; i < n; ++i) { 478 | // 前两个半平面交点p[tail],不在当前半平面内,则删除前一个半平面 479 | while(head < tail && !hp[i].isPointIn(p[tail]) ) 480 | --tail; 481 | // 判断另一侧的半平面交点p[head+1],不在当前半平面内,则进行平面剔除 482 | while(head < tail && !hp[i].isPointIn(p[head+1]) ) 483 | ++head; 484 | // 如果某个时刻 两个反向半平面平行了,必然无解 485 | if(hp[i].isParallelTo(hp[que[tail]])) { 486 | return false; 487 | } 488 | // 将当前半平面压入队列 489 | que[ ++tail ] = i; 490 | p[tail] = hp[i].getCrossPoint(hp[que[tail-1]]); 491 | } 492 | // 4.队列首的那个半平面,需要满足所有点都在它的左边 493 | while(head < tail && !hp[que[head]].isPointIn(p[tail])) 494 | --tail; 495 | while(head < tail && !hp[que[tail]].isPointIn(p[head+1])) 496 | ++head; 497 | // 至少三个半平面才能构成一个封闭区域 498 | return head + 1 < tail; 499 | } 500 | 501 | void HalfPlanes::getConvex(Polygon &convex) { 502 | p[head] = hp[que[head]].getCrossPoint(hp[que[tail]]); 503 | convex.n = tail - head + 1; 504 | for ( int j = head, i = 0 ; j <= tail; i ++, j ++ ) { 505 | convex.p[i] = p[j]; 506 | } 507 | convex.p[ convex.n ] = convex.p[0]; 508 | } 509 | 510 | // 获取多边形的核 511 | // 512 | bool getPolygonKernel(Polygon &poly, Polygon& ansPoly, double movedist, double& area) { 513 | int i; 514 | HalfPlanes &h = HalfPlanes::Instance(); 515 | h.init(); 516 | 517 | // 面积大于0,逆时针 518 | if(poly.area() > 0) { 519 | for(i = 0; i < poly.n; ++i) { 520 | HalfPlane hp(poly.p[i], poly.p[i+1]); 521 | hp.move(movedist); 522 | h.addHalfPlane(hp); 523 | } 524 | }else { 525 | for(i = 0; i < poly.n; ++i) { 526 | HalfPlane hp(poly.p[i+1], poly.p[i]); 527 | hp.move(movedist); 528 | h.addHalfPlane(hp); 529 | } 530 | } 531 | if( h.doIntersection() ) { 532 | h.getConvex(ansPoly); 533 | area = ansPoly.area(); 534 | return true; 535 | }else { 536 | area = 0; 537 | return false; 538 | } 539 | } 540 | 541 | 542 | // 获取多边形的核 543 | bool getPolygonKernel(double lx, double ly, double rx, double ry, Polygon &poly, HalfPlanes& planes, double& area) { 544 | int i; 545 | HalfPlanes &h = HalfPlanes::Instance(); 546 | h.init(); 547 | h.addRectBorder(lx, ly, rx, ry); 548 | h.getHalfPlane(planes); 549 | 550 | if( h.doIntersection() ) { 551 | h.getConvex(poly); 552 | area = poly.area(); 553 | return true; 554 | }else { 555 | area = 0; 556 | return false; 557 | } 558 | } 559 | 560 | Polygon poly[2]; 561 | 562 | int main() { 563 | int i, j; 564 | while(scanf("%d %d", &poly[0].n, &poly[1].n) != EOF) { 565 | double tot = 0; 566 | for(i = 0; i < 2; ++i) { 567 | for(j = 0; j < poly[i].n; ++j) { 568 | poly[i].p[j].read(); 569 | } 570 | poly[i].p[poly[i].n] = poly[i].p[0]; 571 | tot += fabs(poly[i].area()); 572 | } 573 | tot -= poly[0].getPolygonIntersect(poly[1]); 574 | printf("%.2lf\n", tot); 575 | } 576 | return 0; 577 | } 578 | -------------------------------------------------------------------------------- /计算几何/计算几何_线段判交 模板.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/计算几何/计算几何_线段判交 模板.cpp -------------------------------------------------------------------------------- /高等数学/Simpson.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/高等数学/Simpson.cpp -------------------------------------------------------------------------------- /高等数学/最小分数表示趋近.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhereIsHeroFrom/Code_Templates/28d8e3988bcdd3267b56c5baf721845b4c88fcdc/高等数学/最小分数表示趋近.cpp -------------------------------------------------------------------------------- /高等数学/高斯消元 模板.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | #define eps 1e-6 8 | #define MAXL 110 9 | 10 | class GaussMatrix { 11 | public: 12 | int r, c; // r个方程,c个未知数 13 | double d[MAXL][MAXL]; // 增广矩阵 14 | double x[MAXL]; // 解集 15 | /* 16 | d[0][0] * x[0] + d[0][1] * x[1] + ... + d[0][c-1] * x[c-1] = d[0][c]; 17 | d[1][0] * x[0] + d[1][1] * x[1] + ... + d[1][c-1] * x[c-1] = d[1][c]; 18 | ... 19 | ... 20 | d[r-1][0] * x[0] + d[r-1][1] * x[1] + ... + d[r-1][c-1] * x[c-1] = d[r-1][c]; 21 | 22 | */ 23 | 24 | void swap_row(int ra, int rb) { 25 | int i; 26 | for(i = 0; i <= c; i++) { 27 | double tmp = d[ra][i]; 28 | d[ra][i] = d[rb][i]; 29 | d[rb][i] = tmp; 30 | 31 | } 32 | } 33 | 34 | bool zero(double v) { 35 | return fabs(v) < eps; 36 | } 37 | 38 | bool gauss() { 39 | int i, j, k; 40 | int col = 0; // 当前枚举列 41 | int maxrow; // 第col列中绝对值最大的行号 42 | 43 | for(i = 0; i < r && col < c; i++) { 44 | maxrow = i; 45 | for(j = i+1; j < r; j++) { 46 | if( fabs(d[j][col]) > fabs(d[maxrow][col]) ) { 47 | maxrow = j; 48 | } 49 | } 50 | // 将第col列最大的行maxrow和第i行交换,避免误差 51 | if(i != maxrow) swap_row(i, maxrow); 52 | // 如果第col中最大的那行的值为0继续找下一列的 53 | if( zero(d[i][col]) ) { 54 | col ++; 55 | i --; 56 | continue; 57 | } 58 | for(j = i+1; j < r; j++) { 59 | // 将第j行第col列的元素消为0 60 | if( !zero(d[j][col]) ) { 61 | double sub = d[j][col]/d[i][col]; 62 | for(k = col; k <= c; k++) { 63 | d[j][k] = d[j][k] - d[i][k] * sub; // 注意:这一步是关键,精度误差就在这里出现 64 | } 65 | } 66 | } 67 | col++; 68 | } 69 | 70 | // 唯一解 回归 71 | for(i = c-1; i >= 0; i--) { 72 | double sum = 0; 73 | for(j = i+1; j < c; j++) { 74 | sum += x[j] * d[i][j]; 75 | } 76 | x[i] = (d[i][c] - sum) / d[i][i]; 77 | if( zero(x[i]) ) x[i] = 0; 78 | } 79 | return true; 80 | } 81 | void debug_print_x() { 82 | int i; 83 | for(i = 0; i < c; i++) { 84 | printf("%.3lf ", x[i]); 85 | } 86 | puts(""); 87 | } 88 | 89 | void debug_print() { 90 | int i, j; 91 | puts("---------------------------------"); 92 | for(i = 0; i < r; i++) { 93 | for(j = 0; j <= c; j++) { 94 | printf("%.3lf ", d[i][j]); 95 | } 96 | puts(""); 97 | } 98 | puts("---------------------------------"); 99 | } 100 | }; 101 | 102 | 103 | 104 | 105 | 106 | 107 | #include 108 | 109 | using namespace std; 110 | 111 | 112 | #define MAXN 105 113 | #define LL __int64 114 | 115 | /* 116 | PKU 2065 117 | 高斯消元 - 同余方程 118 | 一般只要求求一个解/而且必然有解 119 | */ 120 | 121 | LL GCD(LL a, LL b) { 122 | if(!b) { 123 | return a; 124 | } 125 | return GCD(b, a%b); 126 | } 127 | 128 | LL ExpGcd(LL a, LL b, LL &X, LL &Y) { 129 | LL q, temp; 130 | if( !b ) { 131 | q = a; X = 1; Y = 0; 132 | return q; 133 | }else { 134 | q = ExpGcd(b, a % b, X, Y); 135 | temp = X; 136 | X = Y; 137 | Y = temp - (a / b) * Y; 138 | return q; 139 | } 140 | } 141 | 142 | LL Mod(LL a, LL b, LL c) { 143 | if(!b) { 144 | return 1 % c; 145 | } 146 | return Mod(a*a%c, b/2, c) * ( (b&1)?a:1 ) % c; 147 | } 148 | 149 | class GaussMatrix { 150 | public: 151 | int r, c; 152 | LL d[MAXN][MAXN]; 153 | LL x[MAXN]; // 某个解集 154 | LL xcnt; // 解集个数 155 | 156 | LL abs(LL v) { 157 | return v < 0 ? -v : v; 158 | } 159 | 160 | void swap_row(int ra, int rb) { 161 | for(int i = 0; i <= c; i++) { 162 | int tmp = d[ra][i]; 163 | d[ra][i] = d[rb][i]; 164 | d[rb][i] = tmp; 165 | } 166 | } 167 | void swap_col(int ca, int cb) { 168 | for(int i = 0; i < r; i++) { 169 | int tmp = d[i][ca]; 170 | d[i][ca] = d[i][cb]; 171 | d[i][cb] = tmp; 172 | } 173 | } 174 | 175 | void getAns(LL mod) { 176 | for(int i = r-1; i >= 0; i--) { 177 | LL tmp = d[i][c]; 178 | // d[i][i] * x[i] + (d[i][i+1]*x[i+1] + ... + d[i][c]*x[c]) = K*mod + tmp; 179 | for(int j = i+1; j < c; j++) { 180 | tmp = ((tmp - d[i][j] * x[j]) % mod + mod) % mod; 181 | } 182 | // d[i][i] * x[i] = K * mod + tmp; 183 | // d[i][i] * x[i] + (-K) * mod = tmp; 184 | // a * x[i] + b * (-K) = tmp; 185 | LL X, Y; 186 | ExpGcd(d[i][i], mod, X, Y); 187 | x[i] = ( (X % mod + mod) % mod ) * tmp % mod; 188 | } 189 | } 190 | 191 | // -1 表示无解 192 | LL gauss(LL mod) { 193 | int i, j, k; 194 | int col, maxrow; 195 | 196 | // 枚举行,步进列 197 | for(i = 0, col = 0; i < r && col < c; i++) { 198 | //debug_print(); 199 | maxrow = i; 200 | // 找到i到r-1行中col元素最大的那个值 201 | for(j = i+1; j < r; j++) { 202 | if( abs(d[j][col]) > abs(d[maxrow][col]) ){ 203 | maxrow = j; 204 | } 205 | } 206 | // 最大的行和第i行交换 207 | if(maxrow != i) { 208 | swap_row(i, maxrow); 209 | } 210 | if( d[i][col] == 0 ) { 211 | // 最大的那一行的当前col值 等于0,继续找下一列 212 | col ++; 213 | i--; 214 | continue; 215 | } 216 | 217 | for(j = i+1; j < r; j++) { 218 | if( d[j][col] ) { 219 | // 当前行的第col列如果不为0,则进行消元 220 | // 以期第i行以下的第col列的所有元素都消为0 221 | LL lastcoff = d[i][col]; 222 | LL nowcoff = d[j][col]; 223 | for(k = col; k <= c; k++) { 224 | d[j][k] = (d[j][k] * lastcoff - d[i][k] * nowcoff) % mod; 225 | if (d[j][k] < 0) d[j][k] += mod; 226 | } 227 | } 228 | } 229 | col ++; 230 | } 231 | // i表示从i往后的行的矩阵元素都为0 232 | // 存在 (0 0 0 0 0 0 d[j][c]) (d[j][c] != 0) 的情况,方程无解 233 | for(j = i; j < r; j++) { 234 | if( d[j][c] ) { 235 | return -1; 236 | } 237 | } 238 | // 自由变元数 为 (变量数 - 非零行的数目) 239 | int free_num = c - i; 240 | 241 | // 交换列,保证最后的矩阵为严格上三角,并且上三角以下的行都为0 242 | for(i = 0; i < r && i < c; i++) { 243 | if( !d[i][i] ) { 244 | // 对角线为0 245 | for(j = i+1; j < c; j++) { 246 | // 在该行向后找第一个不为0的元素所在的列,交换i和这一列 247 | if(d[i][j]) break; 248 | } 249 | if(j < c) { 250 | swap_col(i, j); 251 | } 252 | } 253 | } 254 | xcnt = ( ((LL)1) << (LL)free_num ); 255 | 256 | getAns(mod); 257 | return xcnt; 258 | } 259 | 260 | void debug_print() { 261 | int i, j; 262 | printf("-------------------------------\n"); 263 | for(i = 0; i < r; i++) { 264 | for(j = 0; j <= c; j++) { 265 | printf("%d ", d[i][j]); 266 | } 267 | puts(""); 268 | } 269 | printf("-------------------------------\n"); 270 | } 271 | }; 272 | 273 | char str[100]; 274 | int main() { 275 | int t; 276 | int p; 277 | int i, j; 278 | scanf("%d", &t); 279 | while( t-- ) { 280 | scanf("%d %s", &p, str); 281 | GaussMatrix M; 282 | M.r = M.c = strlen(str); 283 | for(i = 0; i < M.r; i++) { 284 | for(j = 0; j <= M.c; j++) { 285 | if(j < M.c) { 286 | M.d[i][j] = Mod(i+1, j, p); 287 | }else { 288 | M.d[i][ M.c ] = (str[i]=='*') ? 0 : (str[i]-'a'+1); 289 | } 290 | } 291 | } 292 | M.gauss(p); 293 | for(i = 0; i < M.c; i++) { 294 | if(i) printf(" "); 295 | printf("%I64d", M.x[i]); 296 | } 297 | puts(""); 298 | } 299 | return 0; 300 | } 301 | 302 | --------------------------------------------------------------------------------