diff --git a/README.md b/README.md new file mode 100644 index 0000000..d08d4a3 --- /dev/null +++ b/README.md @@ -0,0 +1,207 @@ +# ACM_TEMPLATE +ACM模板 + +感谢 *南京大学本科中科院软件所硕士* 退役ACMer、大佬 “发神” 王宪发学长提供的模板。 + +本模板在大佬模板的基础上有大量的增加和改动,以适应自己的需要。 + +## 测过的模板目录: + +### 代码模板 + ++ [**我的代码模板**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/TEMPLATE/My_ACM_Template.cpp) + ++ [**发神的代码模板**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/TEMPLATE/acm_template.cpp) + + + +### 高精度模板 + ++ [**C++大数类(加减乘除取模)**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/高精度/C++大数类(高精度大整数加减乘除取模).cpp) + ++ [**Java高精度与字符串**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/高精度/Java高精度与字符串.java) + + + +### 字符串算法 + ++ #### KMP算法 + + + [**KMP**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/字符串/KMP.cpp) + + + [**KMP最大表示法**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/字符串/KMP最大表示法.cpp) + + + [**KMP最小表示法**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/字符串/KMP最小表示法.cpp) + ++ #### [Manacher算法](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/字符串/Manacher.cpp) + ++ #### [Trie字典树](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/字符串/Trie.cpp) + ++ #### [AC自动机](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/字符串/AC_Automation.cpp) + + + +### 数据结构 + ++ #### [并查集(单点修改、撤销)](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/%E5%8F%AF%E4%BF%AE%E6%94%B9%EF%BC%88%E6%92%A4%E9%94%80%EF%BC%89%E5%B9%B6%E6%9F%A5%E9%9B%86.cpp) + ++ #### 线段树 + + + [**线段树(数组版)**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/数据结构/线段树(数组版).cpp) + + [**线段树(结构体版)**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/数据结构/线段树(结构体版).cpp) + ++ #### [树状数组](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/数据结构/树状数组.cpp) + ++ #### [二维树状数组](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/数据结构/二维树状数组.cpp) + ++ #### [ST表](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/数据结构/ST表RMQ.cpp) + ++ #### [树链剖分](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/数据结构/树链剖分.cpp)(我竟然还学过这个东西???) + + + +### 图论 + ++ #### 最小生成树 + + + [**Prim算法**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/图论/prim.cpp) + + [**Kruskal算法**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/图论/kruskal.cpp) + ++ #### 最短路 + + + [**Dijkstra算法(堆优化)**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/图论/dijkstra.cpp) + + [**Floyd算法**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/图论/floyd.cpp) + + [**SPFA算法**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/图论/spfa.cpp) + + [**差分约束**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/图论/差分约束.cpp) + ++ #### 无向图 + + + [**无向图的割点与桥(Tarjan算法)**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/图论/Tarjan求无向图的割点与桥.cpp) + + [**点-双连通分量**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/图论/点-双连通分量.cpp) + + [**点-双连通分量**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/图论/点-双连通分量.cpp) + + [**点连通度与边连通度**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/图论/点连通度与边连通度.cpp) + ++ #### 有向图 + + + [**有向图判环(DFS染色法)**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/图论/有向图判环(DFS染色法).cpp) + + [**有向图强联通分量(Tarjan算法)**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/图论/有向图强联通分量Tarjan算法.cpp) + ++ #### 二分图 + + + [**判定二分图(染色法)**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/图论/判定二分图(染色法).cpp) + + [**二分图最大匹配匈牙利算法(DFS版)**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/图论/二分图最大匹配匈牙利算法DFS版.cpp) + + [**二分图最大匹配匈牙利算法(BFS版)**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/图论/二分图最大匹配匈牙利算法BFS版.cpp) + + [**二分图最大匹配Hopcroft-Karp算法**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/图论/二分图最大匹配Hopcroft-Karp算法.cpp) + + [**二分图完美匹配KM算法**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/图论/二分图完美匹配KM算法.cpp) + ++ #### LCA + + + [**LCA在线算法(倍增)**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/图论/LCA在线倍增.cpp) + + [**LCA离线算法(Tarjan算法)**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/图论/LCA离线Tarjan算法.cpp) + ++ #### [最小树形图朱刘算法](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/图论/最小树形图朱刘算法.cpp) + ++ #### [全局最小割Stoer_Wagner算法](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/图论/全局最小割Stoer_Wagner算法.cpp) + ++ #### [2-SAT](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/图论/2-SAT.cpp) + + + +### 网络流 + ++ #### 最大流 + + + [**Dinic算法**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/网络流/Dinic.cpp) + + [**SAP**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/网络流/SAP.cpp) + + [**上下界网络流**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/网络流/上下界网络流.cpp) + + [**最少最小割边数**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/网络流/最少最小割边数.cpp) + ++ #### 最小费用最大流 + + + [**MCMF**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/网络流/MCMF.cpp) + + [**zkw费用流**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/网络流/zkw费用流.cpp) + ++ #### [最大权闭合子图](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/网络流/最大权闭合子图.cpp) + + + +### 数学 + ++ #### 数论 + + + [**FFT(快速傅里叶变换)**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/数学/FFT.cpp) + + [**Miller_Robin素性测试+Pollard_rho大数因数分解**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/数学/Miller_Robin素性测试%2BPollard_rho大数因数分解.cpp) + + [**埃氏筛求反素数(线性筛求反素数)**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/数学/埃氏筛求反素数(线性筛求反素数).cpp) + + [**欧拉函数**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/数学/欧拉函数.cpp) + + [**快速幂**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/数学/快速幂.cpp) + + [**矩阵快速幂**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/数学/矩阵模运算(模加法、模乘法、快速幂、模幂和).cpp) + + [**辗转相除法(欧几里得算法)**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/数学/辗转相除法(欧几里得).cpp) + + [**扩展欧几里得算法**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/数学/扩展欧几里得.cpp) + + [**求逆元**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/数学/逆元.cpp) + ++ #### 线性代数 + + + [**高斯消元法(整数)**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/数学/高斯消元法(整数).cpp) + + [**高斯消元法(浮点数)**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/数学/高斯消元法(浮点数).cpp) + + [**高斯消元法(异或)**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/数学/高斯消元法(异或).cpp) + ++ #### 组合数学 + + + [**求组合数**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/数学/组合数.cpp) + + + +### 计算几何 + +[*计算几何模板详细目录*](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/计算几何/计算几何模板目录.txt) + ++ [**A. 点、向量、直线与线段相关算法**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/计算几何/A.%20点、向量、直线与线段相关算法.cpp) + ++ [**B. 圆相关算法**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/计算几何/B.%20圆相关算法.cpp) + ++ [**C. 多边形和凸包相关算法**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/计算几何/C.%20多边形和凸包相关算法.cpp) + ++ [**D. 旋转卡壳**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/计算几何/D.%20旋转卡壳.cpp) + ++ [**E. 半平面交**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/计算几何/E.%20半平面交.cpp) + ++ [**F. 平面直线图**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/计算几何/F.%20平面直线图.cpp) + + + +### 小算法(杂项) + ++ #### Dancing Link(舞蹈链算法) + + + [**DLX 精确覆盖**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/常用小算法汇总/DLX(精确覆盖).cpp) + + [**DLX 重复覆盖**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/常用小算法汇总/DLX(重复覆盖).cpp) + + [**DLX 解数独问题**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/常用小算法汇总/DLX精确覆盖解数独.cpp) + ++ #### [dfs序](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/常用小算法汇总/dfs序.cpp) + ++ #### [二分查找](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/常用小算法汇总/二分查找.cpp) + ++ #### [三分查找](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/常用小算法汇总/三分查找.cpp) + ++ #### [启发式搜索A*算法](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/常用小算法汇总/启发式搜索A_Star.cpp) + ++ #### 动态规划(dp) + + + [**背包问题**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/常用小算法汇总/背包问题(dp).cpp) + + [**最长上升子序列(LIS)**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/常用小算法汇总/最长上升子序列(LIS).cpp) + + [**数位dp(数位统计)**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/常用小算法汇总/数位dp(数位统计).cpp) + + [**树的重心(树形dp)**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/常用小算法汇总/树的重心(树形dp).cpp) + + [**树的直径(两次dfs+树形dp)**](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/常用小算法汇总/树的直径(两次dfs%2B树形dp).cpp) + ++ #### [线性筛法](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/常用小算法汇总/线性筛法.cpp) + ++ #### [线性预处理逆元](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/常用小算法汇总/线性预处理逆元.cpp) + ++ #### [莫队算法](https://github.com/ThoseBygones/ACM_TEMPLATE/blob/master/常用小算法汇总/莫队算法.cpp)(我好像没有学过这个东西却莫名的会用这个模板???) + + + +## 未测过(即将测试)的模板目录: + ++ **斜率dp** ++ 莫队算法(补学一下并更新一下模板) \ No newline at end of file diff --git a/TEMPLATE/My_ACM_Template.cpp b/TEMPLATE/My_ACM_Template.cpp new file mode 100644 index 0000000..2d20744 --- /dev/null +++ b/TEMPLATE/My_ACM_Template.cpp @@ -0,0 +1,68 @@ +/* + ******************************************************************************** + * Author: ThoseBygones + * Version: V1.0 + * Date: + * Subject: ACM-ICPC + * Language: C/C++11 + * OJ: + * Algorithm: + ******************************************************************************** + * Algo-Description: + ******************************************************************************** + */ + +//#pragma comment(linker,"/STACK:102400000,102400000") +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +using namespace std; + +template inline T sqr(T x) {return x * x;} +typedef long long LL; +typedef unsigned long long ULL; +typedef long double LD; +typedef pair PII; +typedef pair PIII; +typedef pair PLL; +typedef pair PLI; +typedef pair PDD; +#define MP make_pair +#define PB push_back +#define sz(x) ((int)(x).size()) +const double EPS = 1e-6; +const int INF = 0x3fffffff; +const LL LINF = INF * 1ll * INF; +const double PI = acos(-1.0); + +#define MOD 1000000007 +#define lson l,mid,rt<<1 +#define rson mid+1,r,rt<<1|1 +#define lowbit(u) (u&(-u)) + + +int main() +{ + return 0; +} diff --git "a/\345\233\276\350\256\272/2-SAT.cpp" "b/\345\233\276\350\256\272/2-SAT.cpp" index 933ce24..121edcd 100644 --- "a/\345\233\276\350\256\272/2-SAT.cpp" +++ "b/\345\233\276\350\256\272/2-SAT.cpp" @@ -1,48 +1,216 @@ -class TwoSat{ +//2-SAT模板 + +/* +x : 选x; ~x : 不选x +x AND y = 1 : ~x -> x, ~y -> y (两个数必须全为1) +x AND y = 0 : x -> ~y, y -> ~x (两个数至少有一个为0) +x OR y = 1 : ~x -> y, ~y -> x (两个数至少有一个为1) +x OR y = 0 : x -> ~x, y -> ~y (两个数全为0) +x XOR y = 1 : x -> ~y, y -> ~x, ~y -> x, ~x -> y (两个数不同) +x XOR y = 0 : x -> y, ~x -> ~y, y -> x, ~y -> ~x (两个数相同) + +x,y不能都选是 : x -> ~y, y -> ~x +x,y不能都选否 : ~x -> y, ~y -> x +x选是且y选否不能同时发生 : x -> y, ~y -> ~x +x选否且y选是不能同时发生 : ~x -> ~y, y -> x +*/ + +#define MAXN 10005 +#define MAXE 2000005 + +class TwoSat +{ public: - int mark[MAXN<<1],s[MAXN<<1]; - int c,cnt; - - //使用前调用 - void init(int n){ - cnt = 0; - for(int i = 0;i<2*n;i++) head[i] = -1,mark[i] = 0; - } - - bool dfs(int x){ - if(mark[x^1]) return false; - if(mark[x]) return true; - mark[x] = true; - s[c++] = x; - for(int i = head[x];~i;i = nxt[i]){ - if(!dfs(e[i])) return false; - } - return true; - } - - inline void addEdge(int u,int v){ - e[cnt] = v; - int tmp = head[u]; - head[u] = cnt; - nxt[cnt++] = tmp; - } - - //n是变量数 - bool solve(int n){ - for(int i = 0;i0) mark[s[--c]] = false; - if(!dfs(i^1)) return false; - } - } - } - return true; - } - - void buildGraph(int n){ - init(n); - } -} twosat; + int head[MAXN<<1]; + struct Edge + { + int to,next; + Edge() {} + Edge(int to,int next):to(to),next(next) {} + } e[MAXE]; + + int mark[MAXN<<1]; //mark[i<<1]==1,表示点i被选择;mark[i<<1|1]==1,表示点i没有被选择 + int cnt,scc_cnt,dfs_clock; + int n,m; + int top; + + stack sta; + vector nG[MAXN]; //缩点后建立的新图 + + int dfn[MAXN<<1]; + int low[MAXN<<1]; + int belong[MAXN<<1]; + int color[MAXN<<1]; //求解任意一组可行解时记录点的颜色 + int sta[MAXN<<1]; //数组模拟栈 + int conf[MAXN<<1]; //记录新图中的冲突点 + int ind[MAXN<<1]; //入度 + + //使用前调用 + void init(int n,int m) + { + this -> n = n; + this -> m = m; + cnt = scc_cnt = dfs_clock = 0; + top = 0; + memset(dfn,0,sizeof(dfn)); + memset(belong,0,sizeof(belong)); + memset(color,0,sizeof(color)); + memset(conf,0,sizeof(conf)); + memset(ind,0,sizeof(ind)); + for(int i=0; i q; + for(int i = 1; i<=scc_cnt; i++) + { + if(!ind[i]) + q.push(i); + } + while(!q.empty()) + { + int u = q.front(); + q.pop(); + if(!color[u]) + { + color[u] = 1; + color[conf[u]] = 2; //conf数组记录的是与当前点冲突的点 + } + for(int i = 0; i0) + mark[sta[--top]] = false; + if(!dfs(i^1)) + return false; + } + } + } + return true; + } + + void buildGraph() + { + memset(head,-1,sizeof(head)); + memset(mark,0,sizeof(mark)); + } +} twosat; diff --git "a/\345\233\276\350\256\272/LCA\345\234\250\347\272\277\345\200\215\345\242\236.cpp" "b/\345\233\276\350\256\272/LCA\345\234\250\347\272\277\345\200\215\345\242\236.cpp" index 91a30b1..8314f12 100644 --- "a/\345\233\276\350\256\272/LCA\345\234\250\347\272\277\345\200\215\345\242\236.cpp" +++ "b/\345\233\276\350\256\272/LCA\345\234\250\347\272\277\345\200\215\345\242\236.cpp" @@ -1,55 +1,99 @@ -class Tree{ +//LCA在线倍增(需要头文件) + +const int MAXN = 100005; +const int MAXE = 200005; + +class LCA_Online_Multiplication +{ public: - #define MAXN 100005 - #define MAXE 200005 - - int head[MAXN],nxt[MAXE],e[MAXE]; - int cnt; - - void init(int n){ - cnt = 0; - for(int i = 0;in = n; - } - - inline void addEdge(int u,int v){ - e[cnt] = v; - int tmp = head[u]; - head[u] = cnt; - nxt[cnt++] = tmp; - } - - int dep[MAXN]; - int p[MAXN][20]; - int n; - - void dfs(int u,int fa,int d){ - dep[u] = d; - p[u][0] = fa; - for(int i = 1;(1<dep[v]) swap(u,v); - if(dep[u]=0;i--){ - if(p[u][i]!=p[v][i]) - u = p[u][i],v = p[v][i]; - } - u = p[u][0],v = p[v][0]; - } - return u; - } -} lca; + + int head[MAXN], nxt[MAXE], e[MAXE]; + int cnt; + + void init(int n) + { + this -> n = n; + cnt = 0; + memset(head, -1, sizeof(head)); + } + + inline void addEdge(int u, int v) + { + e[cnt] = v; + int tmp = head[u]; + head[u] = cnt; + nxt[cnt++] = tmp; + } + + int dep[MAXN]; + int p[MAXN][20]; + int n; + + void dfs(int u, int fa, int d) + { + dep[u] = d; + p[u][0] = fa; + for(int i = 1; (1 << i) <= n; i++) + { + if(~p[u][i - 1]) + p[u][i] = p[p[u][i - 1]][i - 1]; + else + p[u][i] = -1; + } + for(int i = head[u]; ~i; i = nxt[i]) + { + int v = e[i]; + if(v == fa) + continue; + dfs(v, u, d + 1); + } + } + + int LCA(int u, int v) + { + if(dep[u] > dep[v]) + swap(u, v); + if(dep[u] < dep[v]) + { + int offset = dep[v] - dep[u]; + for(int i = 0; (1 << i) <= n; i++) + { + if(offset & (1 << i)) + v = p[v][i]; + } + } + if(u != v) + { + for(int i = log2(n); i >= 0; i--) + { + if(p[u][i] != p[v][i]) + u = p[u][i], v = p[v][i]; + } + u = p[u][0], v = p[v][0]; + } + return u; + } + + //求树上两点距离 + int treeDis(int u, int v) + { + return dep[u] + dep[v] - 2 * dep[LCA(u, v)]; + } + + void buildGraph() + { + for(int i = 1; i < n; i++) + { + int u, v; + scanf("%d%d", &u, &v); + addEdge(u, v); + addEdge(v, u); + } + } + + void solve() + { + buildGraph(); + dfs(1, -1, 0); + } +} lca_multi; diff --git "a/\345\233\276\350\256\272/LCA\347\246\273\347\272\277Tarjan\347\256\227\346\263\225.cpp" "b/\345\233\276\350\256\272/LCA\347\246\273\347\272\277Tarjan\347\256\227\346\263\225.cpp" new file mode 100644 index 0000000..6f67cf9 --- /dev/null +++ "b/\345\233\276\350\256\272/LCA\347\246\273\347\272\277Tarjan\347\256\227\346\263\225.cpp" @@ -0,0 +1,376 @@ +//LCA离线Tarjan算法 + +/*题目给定的是一棵连通的树*/ +#define PB push_back +#define MAXN 40005 +#define MAXQ 100005 + +class LCA_Offline_Tarjan +{ +public: + struct Edge + { + int to,cost,next; + Edge() {} + Edge(int to,int cost,int next):to(to),cost(cost),next(next) {} + } e[MAXN<<1]; + + int head[MAXN]; + int dep[MAXN]; + int fa[MAXN]; + bool vis[MAXN]; + int ans[MAXQ]; + int cnt; + int n,q; + + void addEdge(int u,int v,int w) + { + e[cnt].to = v; + e[cnt].cost = w; + e[cnt].next = head[u]; + head[u] = cnt++; + } + + struct Query + { + int idx; + int u,v; + }; + + vector qry[MAXN]; + + void init(int n,int q) + { + this -> n = n; + this -> q = q; + cnt = 0; + for(int i = 1; i<=n; i++) + { + head[i] = -1; + qry[i].clear(); + fa[i] = i; + vis[i] = false; + } + } + + int findset(int u) + { + return u==fa[u]?u:fa[u] = findset(fa[u]); + } + + int treeDis(int u,int v,int lca) + { + return dep[u] + dep[v] - 2 * dep[lca]; + } + + void dfs(int u,int d) + { + dep[u] = d; + vis[u] = true; + for(int i = head[u]; ~i; i = e[i].next) + { + int v = e[i].to; + if(!vis[v]) + { + dfs(v,d+e[i].cost); + fa[findset(v)] = findset(u); + } + } + int sz = qry[u].size(); + for(int i = 0; i qry[MAXN]; + + void init(int n,int m,int q) + { + this -> n = n; + this -> m = m; + this -> q = q; + cnt = 0; + for(int i = 1; i<=n; i++) + { + head[i] = -1; + qry[i].clear(); + fa[i] = i; + vis[i] = 0; + } + } + + int findset(int u) + { + return u==fa[u]?u:fa[u] = findset(fa[u]); + } + + int treeDis(int u,int v,int lca) + { + return dep[u] + dep[v] - 2 * dep[lca]; + } + + void dfs(int u,int d,int rt) + { + dep[u] = d; + vis[u] = rt; + for(int i = head[u]; ~i; i = e[i].next) + { + int v = e[i].to; + if(!vis[v]) + { + dfs(v,d+e[i].cost); + fa[findset(v)] = findset(u); + } + } + int sz = qry[u].size(); + for(int i = 0; i n = n; + this -> m = m; + this -> q = q; + cnt = cnt2 = 0; + memset(ans,-1,sizeof(ans)); + for(int i = 1; i<=n; i++) + { + head[i] = -1; + head2[i] = -1; + fa[i] = i; + vis[i] = 0; + } + } + + int findset(int u) + { + return u==fa[u]?u:fa[u] = findset(fa[u]); + } + + int treeDis(int u,int v,int lca) + { + return dep[u] + dep[v] - 2 * dep[lca]; + } + + void dfs(int u,int d,int rt) + { + dep[u] = d; + vis[u] = rt; + for(int i = head[u]; ~i; i = e[i].next) + { + int v = e[i].to; + if(!vis[v]) + { + dfs(v,d+e[i].cost,rt); + fa[findset(v)] = findset(u); + } + } + for(int i = head2[u]; ~i; i = qry[i].next) + { + int v = qry[i].v; + if(vis[v]==rt) //判断是否连通,直接给出树的情况可以不用 + { + int lca = findset(v); + ans[i/2] = treeDis(u,v,lca); //输入需要记录的查询内容 + } + } + } + + void buildGraph() + { + for(int i = 0; i= dfn[u]) + cut[u] = true; + if(lowv > dfn[u]) + bridge[i] = true; + } + else if(dfn[v] < dfn[u] && v != fa) + lowu = min(lowu,dfn[v]); + } + if(fa == -1 && child == 1) + cut[u] = 0; + low[u] = lowu; + return lowu; + } + + void buildGraph(int m) + { + /*建图操作,注意无向图应建双向边*/ + } + + void solve(int n,int m) + { + buildGraph(m); + for(int i=0; i>1 +const int MAXN = 1005; +const int MAXE = (MAXN * MAXN); typedef int Type; -class Dijkstra{ +class Dijkstra +{ public: - int head[MAXN],nxt[MAXE],cnt; - Type d[MAXN]; - struct Edge{ - int v; - Type cost; - Edge(){} - Edge(int v,Type cost):v(v),cost(cost){} - bool operator<(const Edge& ed) const{ - return cost>ed.cost; - } - } e[MAXE]; - bool vis[MAXN]; + int head[MAXN], nxt[MAXE], cnt; + Type d[MAXN]; + struct Edge + { + int v; + Type cost; + Edge() {} + Edge(int v, Type cost) : v(v), cost(cost) {} + bool operator < (const Edge& ed) const + { + return cost > ed.cost; + } + } e[MAXE]; + bool vis[MAXN]; + int n, m; - //初始化,n为点数 - void init(int n){ - cnt = 0; - for(int i = 0;i n = n; + this -> m = m; + cnt = 0; + memset(head, -1, sizeof(head)); + } - inline void addEdge(int u,int v,Type cost){ - e[cnt] = Edge(v,cost); - int tmp = head[u]; - head[u] = cnt; - nxt[cnt++] = tmp; - } + inline void addEdge(int u, int v, Type cost) + { + e[cnt] = Edge(v, cost); + int tmp = head[u]; + head[u] = cnt; + nxt[cnt++] = tmp; + } - Type dijkstra(int s,int t,int n){ - for(int i = 0;i q; - q.push(Edge(s,0)); - while(!q.empty()){ - Edge ed = q.top();q.pop(); - vis[ed.v] = true; - if(ed.v==t) return d[t]; - for(int i = head[ed.v];~i;i = nxt[i]){ - Edge ee = e[i]; - if(!vis[ee.v]&&d[ee.v]>d[ed.v]+ee.cost){ - d[ee.v] = d[ed.v]+ee.cost; - /* - * 最短路树 - p[ee.v] = MP(u,i); - */ - q.push(Edge(ee.v,d[ee.v])); - } - } - } - return d[t]; - } -} dij; \ No newline at end of file + //void dijkstra(int s) + Type dijkstra(int s, int t) + { + for(int i = 0; i <= n; i++) + { + d[i] = INF; + vis[i] = false; + } + d[s] = 0; + priority_queue q; + q.push(Edge(s, 0)); + while(!q.empty()) + { + Edge ed = q.top(); + q.pop(); + if(vis[ed.v]) //没有该判断会TLE + continue; + vis[ed.v] = true; + //if(ed.v == t) + // return d[t]; + for(int i = head[ed.v]; ~i; i = nxt[i]) + { + Edge ee = e[i]; + if(!vis[ee.v] && d[ee.v] > d[ed.v] + ee.cost) + { + d[ee.v] = d[ed.v] + ee.cost; + /* + * 最短路树 + p[ee.v] = MP(u,i); + */ + q.push(Edge(ee.v, d[ee.v])); + } + } + } + return d[t]; + } + + void solve() + { + buildGraph(); //建图 + dijkstra(1, n); + } +} dij; diff --git "a/\345\233\276\350\256\272/floyd.cpp" "b/\345\233\276\350\256\272/floyd.cpp" index 07ada9c..5bee18e 100644 --- "a/\345\233\276\350\256\272/floyd.cpp" +++ "b/\345\233\276\350\256\272/floyd.cpp" @@ -1,13 +1,36 @@ +//Floyd(多源最短路)算法,复杂度O(n^3) + Type d[MAXN][MAXN]; int n,m; void floyd(){ - for(int k = 0;kd[i][k]+d[j][k]) d[i][j] = d[i][k]+d[j][k]; } } + } + } +} + +#define INF 0x3f3f3f3f + +Type d[MAXN][MAXN]; +int n,m; + +//memset(d,INF,sizeof(d)); +void floyd() +{ + for(int k=0; k e.cost; + } +} e[MAXE]; + +int head[MAXN]; +Type d[MAXN]; +bool vis[MAXN]; +int cnt; + +inline void addEdge(int u,int v,Type w) +{ + e[cnt].v = v; + e[cnt].cost = w; + e[cnt].nxt = head[u]; + head[u] = cnt++; +} + +Type prim(int n) +{ + priority_queue pq; + for(int i=0; i e[i].cost) + { + d[v] = e[i].cost; + Edge tmp; + tmp.v = v; + tmp.cost = d[v]; + pq.push(tmp); + } + } + } + return sum; +} diff --git "a/\345\233\276\350\256\272/spfa.cpp" "b/\345\233\276\350\256\272/spfa.cpp" index c410f53..642334f 100644 --- "a/\345\233\276\350\256\272/spfa.cpp" +++ "b/\345\233\276\350\256\272/spfa.cpp" @@ -1,47 +1,66 @@ -class SPFA{ + +#define MAXN 1005 +#define MAXE (MAXN*MAXN)>>1 + +typedef int Type; + +class SPFA +{ public: - int head[MAXN],nxt[MAXE],cnt; - Type d[MAXN]; - struct Edge{ - int v; - Type cost; - Edge(){} - Edge(int v,Type cost):v(v),cost(cost){} - } e[MAXE]; + int head[MAXN],nxt[MAXE],cnt; + Type d[MAXN]; + struct Edge + { + int v; + Type cost; + Edge() {} + Edge(int v,Type cost):v(v),cost(cost) {} + } e[MAXE]; - bool inq[MAXN]; + bool inq[MAXN]; - void init(int n){ - cnt = 0; - for(int i = 0;i<=n;i++) head[i] = -1; - } + void init(int n) + { + cnt = 0; + for(int i = 0; i<=n; i++) + head[i] = -1; + } - inline void addEdge(int u,int v,Type cost){ - e[cnt] = Edge(v,cost); - int tmp = head[u]; - head[u] = cnt; - nxt[cnt++] = tmp; - } + inline void addEdge(int u,int v,Type cost) + { + e[cnt] = Edge(v,cost); + int tmp = head[u]; + head[u] = cnt; + nxt[cnt++] = tmp; + } - Type spfa(int s,int t,int n){ - for(int i = 0;i q; - q.push(s); - while(!q.empty()){ - int x = q.front();q.pop(); - inq[x] = false; - for(int i = head[x];~i;i = nxt[i]){ - Edge ed = e[i]; - if(d[ed.v]>d[x]+ed.cost){ - d[ed.v] = d[x]+ed.cost; - if(!inq[ed.v]){ - inq[ed.v] = true; - q.push(ed.v); - } - } - } - } - return d[t]; - } + Type spfa(int s,int t,int n) + //void spfa(int s,int n) + { + for(int i = 0; i q; + q.push(s); + while(!q.empty()) + { + int x = q.front(); + q.pop(); + inq[x] = false; + for(int i = head[x]; ~i; i = nxt[i]) + { + Edge ed = e[i]; + if(d[ed.v]>d[x]+ed.cost) + { + d[ed.v] = d[x]+ed.cost; + if(!inq[ed.v]) + { + inq[ed.v] = true; + q.push(ed.v); + } + } + } + } + return d[t]; //如果未给出终点t,则完全可以不要跟t有关的语句 + } } spfa; diff --git "a/\345\233\276\350\256\272/\344\272\214\345\210\206\345\233\276\345\256\214\347\276\216\345\214\271\351\205\215KM\347\256\227\346\263\225.cpp" "b/\345\233\276\350\256\272/\344\272\214\345\210\206\345\233\276\345\256\214\347\276\216\345\214\271\351\205\215KM\347\256\227\346\263\225.cpp" index 2871cda..4f09ab1 100644 --- "a/\345\233\276\350\256\272/\344\272\214\345\210\206\345\233\276\345\256\214\347\276\216\345\214\271\351\205\215KM\347\256\227\346\263\225.cpp" +++ "b/\345\233\276\350\256\272/\344\272\214\345\210\206\345\233\276\345\256\214\347\276\216\345\214\271\351\205\215KM\347\256\227\346\263\225.cpp" @@ -1,58 +1,86 @@ -#define MAXN 105 -int w[MAXN][MAXN],match[MAXN],slack[MAXN],lx[MAXN],ly[MAXN]; +#define MAXN 205 + +int w[MAXN][MAXN]; //邻接矩阵 +int match[MAXN],slack[MAXN],lx[MAXN],ly[MAXN]; //下标从0开始 int visx[MAXN],visy[MAXN]; -int nx,ny;//左右集合的点数 +int nx,ny; //左右集合的点数 -bool find(int u){ +bool find(int u) +{ visx[u] = true; - for(int i = 0;ivɴdy[v]=dx[u]+1dy,dxʾڸԼı + int vis[MAXN]; //Ѱ·ı + int dis; + + + void addEdge(int u,int v) + { + edge[cnt].to=v; + edge[cnt].next=head[u]; + head[u]=cnt++; + } + + bool bfs() //Ѱ·ÿֻѰҵǰ̵· + { + queue q; + dis = INF; + memset(dx,-1,sizeof(dx)); + memset(dy,-1,sizeof(dy)); + for(int i=1; i<=nx; i++) + { + if(mx[i]==-1) //δĽڵӣʼνڵΪ0 + { + q.push(i); + dx[i]=0; + } + } + while(!q.empty()) + { + int u = q.front(); + q.pop(); + if(dx[u]>dis) + break; + for(int i=head[u]; i!=-1; i=edge[i].next) + { + int v = edge[i].to; + if(dy[v] == -1) + { + dy[v] = dx[u] + 1; + if(my[v] == -1) //ҵһ·disΪ·յı + dis = dy[v]; + else + { + dx[my[v]] = dy[v]+1; + q.push(my[v]); + } + } + } + } + return dis!=INF; + } + + bool dfs(int u) + { + for(int i=head[u]; i!=-1; i=edge[i].next) + { + int v = edge[i].to; + if(!vis[v] && dy[v]==dx[u]+1) //õûбҾΪһڵ+1 + { + vis[v]=1; + if(my[v]!=-1 && dy[v]==dis) //uѱƥѵдڵ·յıţٵݹѰҲ·ֱ + continue; + if(my[v]==-1 || dfs(my[v])) //رҪע⣬Mx[u] == -1 && dfs(u)Ⱥ˳ǧܻdfs֮Mx[u]ͻ仯 + { + my[v]=u; + mx[u]=v; + return true; + } + } + } + return false; + } + +public: + void init() + { + cnt = 0; + memset(mx,-1,sizeof(mx)); + memset(my,-1,sizeof(my)); + } + + int maxMatch() //ƥ + { + int ans = 0; + while(bfs()) + { + memset(vis,0,sizeof(vis)); + for(int i=1; i<=nx; i++) + { + if(mx[i]==-1 && dfs(i)) + ans++; + } + } + return ans; + } + + void buildGraph() + { + memset(head,-1,sizeof(head)); + node = nx + ny; + } +} hk; diff --git "a/\345\233\276\350\256\272/\344\272\214\345\210\206\345\233\276\346\234\200\345\244\247\345\214\271\351\205\215\345\214\210\347\211\231\345\210\251\347\256\227\346\263\225BFS\347\211\210.cpp" "b/\345\233\276\350\256\272/\344\272\214\345\210\206\345\233\276\346\234\200\345\244\247\345\214\271\351\205\215\345\214\210\347\211\231\345\210\251\347\256\227\346\263\225BFS\347\211\210.cpp" new file mode 100644 index 0000000..005a9d4 --- /dev/null +++ "b/\345\233\276\350\256\272/\344\272\214\345\210\206\345\233\276\346\234\200\345\244\247\345\214\271\351\205\215\345\214\210\347\211\231\345\210\251\347\256\227\346\263\225BFS\347\211\210.cpp" @@ -0,0 +1,100 @@ +//Hungaryͼƥ䣩㷨BFS棩 + +#define MAXN 1005 +#define MAXE 100005 + + +//ϡͼ٣BFS +class Hungary_BFS +{ +private: + int head[MAXN]; + struct Edge + { + int to,next; + Edge(int to,int next):to(to),next(next) {} + Edge() {} + } e[MAXE]; + + int mx[MAXN],my[MAXN]; + int vis[MAXN]; + int pre[MAXN]; + int n; + int nx,ny; + int cnt; + + void addEdge(int u,int v) + { + e[cnt].to = v; + e[cnt].next = head[u]; + head[u] = cnt++; + } + + + bool bfs(int st) + { + queue q; + q.push(st); + pre[st] = -1; + bool flag = false; + while(!q.empty() && !flag) + { + int u = q.front(); + q.pop(); + for(int i = head[u]; ~i && !flag; i = e[i].next) + { + int v = e[i].to; + if(vis[v] != st) + { + vis[v] = st; + q.push(my[v]); + if(~my[v]) //my[v]!=-1 + pre[my[v]] = u; + else + { + int a = u, b = v; + flag = true; + while(~a) //a!=-1 + { + int t = mx[a]; + mx[a] = b; + my[b] = a; + a = pre[a]; + b = t; + } + } + } + } + } + return mx[st] != -1; + } + +public: + void init() + { + cnt = 0; + } + + int hungary() + { + int res = 0; + memset(mx, -1, sizeof(mx)); + memset(my, -1, sizeof(my)); + memset(vis, -1, sizeof(vis)); + for(int i = 1; i <= nx; i++) //number from 1 + { + if(mx[i] == -1) + { + if(bfs(i)) + res++; + } + } + return res; + } + + void buildGraph() + { + memset(head,-1,sizeof(head)); + n = nx + ny; + } +} hungaryBFS; diff --git "a/\345\233\276\350\256\272/\344\272\214\345\210\206\345\233\276\346\234\200\345\244\247\345\214\271\351\205\215\345\214\210\347\211\231\345\210\251\347\256\227\346\263\225DFS\347\211\210.cpp" "b/\345\233\276\350\256\272/\344\272\214\345\210\206\345\233\276\346\234\200\345\244\247\345\214\271\351\205\215\345\214\210\347\211\231\345\210\251\347\256\227\346\263\225DFS\347\211\210.cpp" new file mode 100644 index 0000000..ed65037 --- /dev/null +++ "b/\345\233\276\350\256\272/\344\272\214\345\210\206\345\233\276\346\234\200\345\244\247\345\214\271\351\205\215\345\214\210\347\211\231\345\210\251\347\256\227\346\263\225DFS\347\211\210.cpp" @@ -0,0 +1,201 @@ +//Hungaryͼƥ䣩㷨DFS棩 + +#define MAXN 1005 +#define MAXE 100005 + + +//ڳͼDFS· + + +//ڽӾ +class Hungary_DFS +{ +private: + int g[MAXN][MAXN]; + int vis[MAXN]; + int mx[MAXN],my[MAXN]; + int n; + int nx,ny; + + bool dfs(int u) + { + for(int v = 1; v <= ny; v++) + { + if(!vis[v] && g[u][v]) + { + vis[v] = true; + if(my[v] == -1 || dfs(my[v])) + { + my[v] = u; + mx[u] = v; + return true; + } + } + } + return false; + } + +public: + void init() + { + memset(mx, -1, sizeof(mx)); + memset(my, -1, sizeof(my)); + } + + int hungary() + { + int res = 0; + for(int i = 1; i <= nx; i++) + { + if(mx[i] == -1) + { + memset(vis, 0, sizeof(vis)); + if(dfs(i)) + res++; + } + } + return res; + } + + void buildGraph() + { + memset(g,0,sizeof(g)); + } +} hungaryDFS; + + + +//ڽӱ +class Hungary_DFS +{ +private: + int head[MAXN]; + struct Edge + { + int to,next; + Edge(int to,int next):to(to),next(next) {} + Edge() {} + } e[MAXE]; + + int mx[MAXN],my[MAXN]; + int vis[MAXN]; + int n; + int nx,ny; + int cnt; + + void addEdge(int u,int v) + { + e[cnt].to = v; + e[cnt].next = head[u]; + head[u] = cnt++; + } + + + bool dfs(int u) + { + for(int i = head[u]; ~i; i = e[i].next) + { + int v = e[i].to; + if(!vis[v]) + { + vis[v] = true; + if(my[v] == -1 || dfs(my[v])) + { + my[v] = u; + mx[u] = v; + return true; + } + } + } + return false; + } + +public: + void init() + { + cnt = 0; + } + + int hungary() + { + int res = 0; + memset(mx, -1, sizeof(mx)); + memset(my, -1, sizeof(my)); + for(int i = 1; i <= nx; i++) + { + if(mx[i] == -1) + { + memset(vis, 0, sizeof(vis)); + if(dfs(i)) + res++; + } + } + return res; + } + + void buildGraph() + { + memset(head,-1,sizeof(head)); + n = nx + ny; + } +} hungaryDFS; + + + +//STL +class Hungary_DFS +{ +private: + vector G[MAXN]; + int vis[MAXN]; + int mx[MAXN],my[MAXN]; + int n; + int nx,ny; + + bool dfs(int u) + { + for(int i = 0; i < G[u].size(); i++) + { + int v = G[u][i]; + if(!vis[v]) + { + vis[v] = true; + if(my[v] == -1 || dfs(my[v])) + { + my[v] = u; + mx[u] = v; + return true; + } + } + } + return false; + } + +public: + void init() + { + memset(mx, -1, sizeof(mx)); + memset(my, -1, sizeof(my)); + } + + int hungary() + { + int res = 0; + for(int i = 1; i <= nx; i++) + { + if(mx[i] == -1) + { + memset(vis, 0, sizeof(vis)); + if(dfs(i)) + res++; + } + } + return res; + } + + void buildGraph() + { + for(int i=0; i<=n; i++) + G[i].clear(); + } +} hungaryDFS; diff --git "a/\345\233\276\350\256\272/\345\205\250\345\261\200\346\234\200\345\260\217\345\211\262Stoer_Wagner\347\256\227\346\263\225.cpp" "b/\345\233\276\350\256\272/\345\205\250\345\261\200\346\234\200\345\260\217\345\211\262Stoer_Wagner\347\256\227\346\263\225.cpp" new file mode 100644 index 0000000..d7c5b19 --- /dev/null +++ "b/\345\233\276\350\256\272/\345\205\250\345\261\200\346\234\200\345\260\217\345\211\262Stoer_Wagner\347\256\227\346\263\225.cpp" @@ -0,0 +1,64 @@ +//Stoer_Wagner(全局最小割)算法,复杂度O(n^3) + +#define MAXN 1005 +#define INF 0x3f3f3f3f + +int g[MAXN][MAXN]; +int v[MAXN],dis[MAXN]; //v数组是马甲数组,dis数组用来表示该点与A集合中所有点之间的边的长度之和 +bool vis[MAXN]; //用来标记是否该点加入了A集合 + +int Stoer_Wagner(int n) +{ + int i, j, res = INF; + for(i = 0; i < n; i ++) + v[i] = i; //初始马甲为自己 + while(n > 1) + { + int k, pre = 0; //pre用来表示之前加入A集合的点,我们每次都以0点为第一个加入A集合的点 + memset(vis, 0, sizeof(vis)); + memset(dis, 0, sizeof(dis)); + for(i = 1; i < n; i ++) + { + k = -1; + for(j = 1; j < n; j ++) //根据之前加入的点,要更新dis数组,并找到最大的dis + if(!vis[v[j]]) + { + dis[v[j]] += g[v[pre]][v[j]]; + if(k == -1 || dis[v[k]] < dis[v[j]]) + k = j; + } + vis[v[k]] = true; //标记该点已经加入A集合 + if(i == n - 1) //最后一次加入的点就要更新答案了 + { + res = min(res, dis[v[k]]); + for(j = 0; j < n; j ++) //将该点合并到pre上,相应的边权就要合并 + { + g[v[pre]][v[j]] += g[v[j]][v[k]]; + g[v[j]][v[pre]] += g[v[j]][v[k]]; + } + v[k] = v[-- n]; //删除最后一个点 + } + pre = k; + } + } + return res; +} + +int main() +{ + int n, m, u, v, w; + while(~scanf("%d%d", &n, &m)) + { + memset(g, 0, sizeof(g)); + while(m--) + { + scanf("%d%d%d", &u, &v, &w); + u--; //顶点编号从0开始 + v--; + g[u][v] += w; + g[v][u] += w; + } + printf("%d\n", Stoer_Wagner(n)); + } + return 0; +} diff --git "a/\345\233\276\350\256\272/\345\210\244\345\256\232\344\272\214\345\210\206\345\233\276\357\274\210\346\237\223\350\211\262\346\263\225\357\274\211.cpp" "b/\345\233\276\350\256\272/\345\210\244\345\256\232\344\272\214\345\210\206\345\233\276\357\274\210\346\237\223\350\211\262\346\263\225\357\274\211.cpp" index ee2dfd4..7eae4e4 100644 --- "a/\345\233\276\350\256\272/\345\210\244\345\256\232\344\272\214\345\210\206\345\233\276\357\274\210\346\237\223\350\211\262\346\263\225\357\274\211.cpp" +++ "b/\345\233\276\350\256\272/\345\210\244\345\256\232\344\272\214\345\210\206\345\233\276\357\274\210\346\237\223\350\211\262\346\263\225\357\274\211.cpp" @@ -1,26 +1,61 @@ + +/* +直接调用checkBipartite(n)函数 +注意点的下标从0开始 +*/ + +#define MAXN 1005 +#define MAXE 200005 + +struct Edge +{ + int to,nxt; + Edge() {} + Edge(int to,int nxt):to(to),nxt(nxt) {} +} e[MAXE]; + +int head[MAXN]; +int cnt; + +inline void addEdge(int u,int v) +{ + e[cnt].to = v; + e[cnt].nxt = head[u]; + head[u] = cnt++; +} + int color[MAXN]; -bool bipartite(int u){ - for(int i = head[u];~i;i = nxt[i]){ - int v = e[i]; - if(color[v]==color[u]) return false; - if(!color[v]){ - color[v] = 3-color[u]; - if(!bipartite(v)) return false; - } - } - return true; +bool bipartite(int u) +{ + for(int i = head[u]; ~i; i = e[i].nxt) + { + int v = e[i].to; + if(color[v] == color[u]) + return false; + if(!color[v]) + { + color[v] = 3 - color[u]; + if(!bipartite(v)) + return false; + } + } + return true; } -bool checkBipartite(int n){ - memset(color,0,sizeof(color)); - bool ok = true; - FOR(i,n){ - if(!color[i]){ - color[i] = 1; - if(!bipartite(i)) ok = false; - } - } - return ok; +bool checkBipartite(int n) +{ + memset(color,0,sizeof(color)); + bool ok = true; + for(int i=0; i=pre[u]) cut[u] = true; - if(lowv>pre[u]) bridge[i] = true; - }else if(pre[v]i,权值c),求最短路 - * 差分约束求xi的最小值,化为xi-xj>=c的形式,加边(j->i,权值c),求最长路 - * */ - Type spfa(int s,int t,int n){ - for(int i = 0;i q; - q.push(s); - while(!q.empty()){ - int x = q.front();q.pop(); - inq[x] = false; - for(int i = head[x];~i;i = nxt[i]){ - Edge ed = e[i]; - if(d[ed.v]n) return -INF; - inq[ed.v] = true; - q.push(ed.v); - } - } - } - } - return d[t]; - } -} cha; + int inqcnt[MAXN]; + /* + * 差分约束求 xi 的最大值,化为 xi - xj <= c 的形式,加边 (j->i, 权值c),求最短路 + * 差分约束求 xi 的最小值,化为 xi - xj >= c 的形式,加边 (j->i, 权值c),求最长路 + */ + Type spfa(int s, int t, int n) //n的值一般传的大一些(至少n+1) + { + for(int i = 0; i <= n; i++) + { + inq[i] = false; + d[i] = INF; //求最长路的时候值改为-INF + inqcnt[i] = 0; + } + d[s] = 0; + queue q; + q.push(s); + while(!q.empty()) + { + int x = q.front(); + q.pop(); + inq[x] = false; + for(int i = head[x]; ~i; i = nxt[i]) + { + Edge ed = e[i]; + if(d[ed.v] > d[x] + ed.cost) //求最长路的时候改成 < 号 + { + d[ed.v] = d[x] + ed.cost; + if(!inq[ed.v]) + { + if(++inqcnt[ed.v] > n) + return INF; + inq[ed.v] = true; + q.push(ed.v); + } + } + } + } + return d[t]; + } +} dc; diff --git "a/\345\233\276\350\256\272/\346\234\200\345\260\217\346\240\221\345\275\242\345\233\276\346\234\261\345\210\230\347\256\227\346\263\225.cpp" "b/\345\233\276\350\256\272/\346\234\200\345\260\217\346\240\221\345\275\242\345\233\276\346\234\261\345\210\230\347\256\227\346\263\225.cpp" new file mode 100644 index 0000000..8aab535 --- /dev/null +++ "b/\345\233\276\350\256\272/\346\234\200\345\260\217\346\240\221\345\275\242\345\233\276\346\234\261\345\210\230\347\256\227\346\263\225.cpp" @@ -0,0 +1,86 @@ + +#define MAXN 1005 +#define MAXE MAXN*MAXN + +typedef LL Type; + +struct Edge//边的权和顶点 +{ + int u,v; + Type w; + Edge() {} + Edge(int u,int v,Type w):u(u),v(v),w(w) {} +} e[MAXE]; + +int pre[MAXN],id[MAXN],vis[MAXN]; +int n,m,pos; +Type in[MAXN]; //存最小入边权,pre[v]为该边的起点 + +Type DMST(int root, int n, int m) //n为总结点数,m为总边数 +{ + Type ret = 0; //存最小树形图总权值 + while(true) + { + //1.找每个节点的最小入边 + for(int i=0; i s; - - void tarjan(int u){ - pre[u] = lowlink[u] = ++dfs_clock; - s.push(u); - for(int i = head[u];~i;i = nxt[i]){ - int v = e[i]; - if(!pre[v]){ - tarjan(v); - lowlink[u] = min(lowlink[u],lowlink[v]); - }else if(!sccno[v]){ - lowlink[u] = min(lowlink[u],pre[v]); - } - } - if(lowlink[u]==pre[u]){ - scc_cnt++; - for(;;){ - int x = s.top();s.pop(); - sccno[x] = scc_cnt; - if(x==u) break; - } - } - } - - //求有向图的强联通分量 - void find_scc(int n){ - dfs_clock = scc_cnt = 0; - for(int i = 0;i sta; + vector nG[MAXN]; //缩点后得到的新图 + + int n,m; + int cnt; + int dfs_clock,scc_cnt; + + void init(int n,int m) + { + this -> n = n; + this -> m = m; + dfs_clock = scc_cnt = 0; + memset(dfn,0,sizeof(dfn)); + memset(belong,0,sizeof(belong)); + } + + void tarjan(int u) + { + dfn[u] = low[u] = ++dfs_clock; + sta.push(u); + //instack[u] = true; + for(int i = head[u]; ~i; i = e[i].next) + { + int v = e[i].to; + if(!dfn[v]) + { + tarjan(v); + low[u] = min(low[u],low[v]); + } + //else if(instack[v]) + else if(!belong[v]) + low[u] = min(low[u],dfn[v]); + } + if(dfn[u]==low[u]) + { + scc_cnt++; + while(!sta.empty()) + { + int temp = sta.top(); + //instack[v] = false; + belong[temp] = scc_cnt; + sta.pop(); + if(u==temp) + break; + } + } + } + + void get_scc() //缩点 + { + memset(ind,0,sizeof(ind)); + memset(outd,0,sizeof(outd)); + for(int i = 1; i<=n; i++) + { + for(int j = head[i]; ~j; j = e[j].next) + { + int v = e[j].to; + if(belong[i]!=belong[v]) + { + ind[belong[v]]++; + outd[belong[i]]++; + nG[belong[i]].push_back(belong[v]); + } + } + } + } + + /*判断缩点后得到的DAG是否为单链(DAG图是否弱连通)*/ + bool topoSort() //拓扑排序 + { + queue q; + for(int i = 1; i<=scc_cnt; i++) + { + if(!ind[i]) + q.push(i); + } + if(q.size()>1) //入度为0的点超过1个 + return false; + while(!q.empty()) + { + int u = q.front(); + q.pop(); + for(int i = 0; i1) + return false; + } + return true; + } + + void buildGraph() + { + cnt = 0; + memset(head,-1,sizeof(head)); + } + + void solve() //求有向图的强连通分量 + { + buildGraph(); + for(int i = 1; i<=n; i++) //点的编号从1开始 + { + if(!dfn[i]) + tarjan(i); + } + } +} scc; diff --git "a/\345\233\276\350\256\272/\347\202\271-\345\217\214\350\201\224\351\200\232\345\210\206\351\207\217.cpp" "b/\345\233\276\350\256\272/\347\202\271-\345\217\214\350\201\224\351\200\232\345\210\206\351\207\217.cpp" deleted file mode 100644 index 282b022..0000000 --- "a/\345\233\276\350\256\272/\347\202\271-\345\217\214\350\201\224\351\200\232\345\210\206\351\207\217.cpp" +++ /dev/null @@ -1,63 +0,0 @@ -class BCC{ -public: - stack s;//存储在当前BCC中的边 - int dfs_clock,bcc_cnt; - int pre[MAXN],cut[MAXN],bccno[MAXN]; - vector bcc_nodes; - PII bcc_edges[MAXE]; - - //返回边数 - int get_bcc(PII ed){ - bcc_cnt++; - bcc_nodes.clear(); - int tot = 0; - while(true){ - PII x = s.top();s.pop(); - int u = x.first,v = x.second; - if(bccno[u]!=bcc_cnt){ - bccno[u] = bcc_cnt; - bcc_nodes.PB(u); - } - if(bccno[v]!=bcc_cnt){ - bccno[v] = bcc_cnt; - bcc_nodes.PB(v); - } - bcc_edges[tot++] = x; - if(x==ed) break; - } - return tot; - } - - int dfs(int u,int fa){ - int lowu = pre[u] = ++dfs_clock; - int child = 0; - for(int i = head[u];~i;i = nxt[i]){ - int v = e[i]; - PII ed = MP(u,v); - if(!pre[v]){ - s.push(ed); - child++; - int lowv = dfs(v,u); - lowu = min(lowu,lowv); - if(lowv>=pre[u]){ - cut[u] = true; - int m = get_bcc(ed); - //m为当前bcc的边数,bcc_nodes记录结点,bcc_edges记录边 - } - }else if(pre[v] s;//存储在当前BCC中的边 + int dfs_clock,bcc_cnt; + int dfn[MAXN]; + int low[MAXN]; + int cut[MAXN]; + int bccno[MAXN]; + vector bcc_nodes; + PII bcc_edges[MAXE]; + int n,m; + int cnt; + + void init(int n,int m) + { + this -> n = n; + this -> m = m; + cnt = 0; + memset(head,-1,sizeof(head)); + memset(dfn,0,sizeof(dfn)); + memset(bccno,0,sizeof(bccno)); + memset(cut,0,sizeof(cut)); + } + + void addEdge(int u,int v) + { + e[cnt].to = v; + e[cnt].next = head[u]; + head[u] = cnt++; + } + + //返回边数 + int get_bcc(PII ed) + { + bcc_cnt++; + bcc_nodes.clear(); + int tot = 0; + while(true) + { + PII x = s.top(); + s.pop(); + int u = x.first,v = x.second; + if(bccno[u]!=bcc_cnt) + { + bccno[u] = bcc_cnt; + bcc_nodes.PB(u); + } + if(bccno[v]!=bcc_cnt) + { + bccno[v] = bcc_cnt; + bcc_nodes.PB(v); + } + bcc_edges[tot++] = x; + if(x==ed) + break; + } + return tot; + } + + void tarjan(int u,int fa) + { + low[u] = dfn[u] = ++dfs_clock; + int child = 0; + for(int i = head[u]; ~i; i = e[i].next) + { + int v = e[i].to; + PII ed = MP(u,v); + if(!dfn[v]) + { + s.push(ed); + child++; + tarjan(v,u); + low[u] = min(low[u],low[v]); + if(low[v]>=dfn[u]) + { + cut[u] = true; + int m = get_bcc(ed); + //m为当前bcc的边数,bcc_nodes记录结点,bcc_edges记录边 + } + } + else if(dfn[v] dinic/SAP;需要枚举源汇点:图论 -> 全局最小割Stoer_Wagner算法 + +2. 有向图的点连通度: + * 需要拆点。原图中的每个点i在网络中拆成入点i'与出点i''; + * 连边,容量为1(例外,容量为正无穷); + * 原图中的每条边在网络中为边,容量为正无穷; + * 求得以s'为源点,t''为汇点求最小割(最大流)即为原图的点连通度。 + * 注:显然容量为正无穷的边不可能通过最小割,即原图中的边和s、t两个点不能删去;若边通过最小割,则表示将原图中的点i删去。 + 【需要模板】若源汇点确定:最大流 -> dinic/SAP; + +3. 无向图的边连通度: + 将图中的每条无向边(i, j)拆成两条有向边,再按照求有向图的边连通度(1)处理。 + 【需要模板】若源汇点确定:最大流 -> dinic/SAP;需要枚举源汇点:图论 -> 全局最小割Stoer_Wagner算法 + +4. 无向图的点连通度: + 将图中的每条无向边(i, j)拆成两条有向边,再按照求有向图的点连通度(2)处理。 + 【需要模板】若源汇点确定:最大流 -> dinic/SAP +*/ diff --git "a/\345\233\276\350\256\272/\347\246\273\347\272\277LCA.cpp" "b/\345\233\276\350\256\272/\347\246\273\347\272\277LCA.cpp" deleted file mode 100644 index d602749..0000000 --- "a/\345\233\276\350\256\272/\347\246\273\347\272\277LCA.cpp" +++ /dev/null @@ -1,131 +0,0 @@ -//#pragma comment(linker,"/STACK:102400000,102400000") -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -using namespace std; -template inline T sqr(T x) { return x * x; } -typedef long long LL; -typedef unsigned long long ULL; -typedef long double LD; -typedef pair PII; -typedef pair PIII; -typedef pair PLL; -typedef pair PLI; -typedef pair PDD; -#define MP make_pair -#define PB push_back -#define sz(x) ((int)(x).size()) -#define clr(ar,val) memset(ar, val, sizeof(ar)) -#define istr stringstream -#define FOR(i,n) for(int i=0;i<(n);++i) -const double EPS = 1e-6; -const int INF = 0x3fffffff; -const LL LINF = INF * 1ll * INF; -const double PI = acos(-1.0); - -using namespace std; - -#define MAXN 40005 - -struct Edge{ - int v,w; - Edge(){} - Edge(int v,int w):v(v),w(w){} -} e[MAXN<<1]; - -int head[MAXN],next[MAXN<<1],d[MAXN],fa[MAXN],ans[205]; -bool vis[MAXN]; -int cnt; - -void addEdge(int u,int v,int w){ - e[cnt] = Edge(v,w); - int tmp = head[u]; - head[u] = cnt; - next[cnt++] = tmp; -} - -struct Query{ - int idx; - int u,v; -}; - -vector q[MAXN]; - -int find(int u){ - return u==fa[u]?u:fa[u] = find(fa[u]); -} - -void dfs(int u,int d){ - ::d[u] = d; - vis[u] = true; - for(int i = head[u];~i;i = next[i]){ - int v = e[i].v; - if(!vis[v]){ - dfs(v,d+e[i].w); - fa[find(v)] = find(u); - } - } - int sz = q[u].size(); - for(int i = 0;ipre[u]){ - bridge[i] = bridge[i^1] = true; - } - }else if(pre[v]dfn[u]) + bridge[i] = bridge[i^1] = true; + } + else if(dfn[v] q; - for(int i = 0;i=0){ - ans+=nd[ptr].count; - nd[ptr].count = -1; + while(ptr != root) + { + if(nd[ptr].cnt >= 0) + { + ans += nd[ptr].cnt; + nd[ptr].cnt = -1; ptr = nd[ptr].fail; - }else break; + } + else + break; } } return ans; } -}; +} ac_auto; diff --git "a/\345\255\227\347\254\246\344\270\262/KMP.cpp" "b/\345\255\227\347\254\246\344\270\262/KMP.cpp" index bef10f4..efcaa68 100644 --- "a/\345\255\227\347\254\246\344\270\262/KMP.cpp" +++ "b/\345\255\227\347\254\246\344\270\262/KMP.cpp" @@ -1,24 +1,33 @@ -int getFail(char* p,int *f){ - int m = strlen(p); - f[0] = f[1] = 0; - for(int i = 1;is[(j+k)%len]) + i = max(i+k+1,j); + else + j = max(j+k+1,i); + if(i==j) + j++; + k = 0; + } + } + return min(i,j); +} diff --git "a/\345\255\227\347\254\246\344\270\262/Manacher.cpp" "b/\345\255\227\347\254\246\344\270\262/Manacher.cpp" index d5a6772..af33f8a 100644 --- "a/\345\255\227\347\254\246\344\270\262/Manacher.cpp" +++ "b/\345\255\227\347\254\246\344\270\262/Manacher.cpp" @@ -1,27 +1,51 @@ -//r[i]表示i的回文半径 -int manacher(char *c){ - int n,j; - int max=0; - str[0]='$'; - for(n=0,j=1; c[n]!='\0'; n++) - { - str[j++]='#'; - str[j++]=c[n]; - } - str[j]='#'; - str[j+1]='\0'; - if(n==0) continue; - int mx=0,id=0; - for(int i=1; i<=j; i++) - { - if(mx>i) r[i] = MIN(r[2*id-i], mx-i); - else r[i]=1; - for(;str[i+r[i]] == str[i-r[i]]; r[i]++); - if(r[i]>max) max=r[i]; - if(r[i]+i>mx){ - mx=r[i]+i; - id=i; - } - } - return max-1; +//Manacher算法 + +char newstr[MAXN<<1]; //转换后的新字符串 +int rad[MAXN<<1]; //rad[i]表示i的回文半径 + +int manacher(char *str) +{ + int j; + int Max = 0; + newstr[0] = '$'; //字符串开头增加一个特殊字符,防止越界 + int len; + //int len = strlen(str); + //for(int k=0; k i) + rad[i] = min(rad[2*id-i],mx-i); //在rad[j]和mx-i中取值小的 + else + rad[i] = 1; //若i>=mx,则要重新计算rad[i] + while(newstr[i+rad[i]] == newstr[i-rad[i]]) //不需边界判断,因为左有'$',右有'\0' + rad[i]++; + Max = max(Max,rad[i]); + /*if(Max < rad[i]) + { + Max = rad[i]; + axis = i; //记录最大回文串对称中心(对称轴) + l = (i - rad[i]) / 2; + r = (i + rad[i]) / 2 - 2; + } + */ + if(rad[i] + i > mx) //若新得到的回文串右端点位置大于mx,则要更新id和mx的值 + { + mx = rad[i] + i; + id = i; + } + } + return Max - 1; //返回rad[i]中的最大值-1即为原串的最长回文子串的长度 } diff --git "a/\345\255\227\347\254\246\344\270\262/Trie.cpp" "b/\345\255\227\347\254\246\344\270\262/Trie.cpp" index bccd2a7..395a70b 100644 --- "a/\345\255\227\347\254\246\344\270\262/Trie.cpp" +++ "b/\345\255\227\347\254\246\344\270\262/Trie.cpp" @@ -1,50 +1,107 @@ +//字典树(Trie)模板 -class Trie{ +#define DIGIT_NUM 32 //数位数量,int为32,long long为64 +#define INF 0x3fffffff + +class Trie +{ public: - #define CHAR_NUM 26 - #define MAXNODE 500005 - - struct node{ - int next[CHAR_NUM]; - int val; - void init(){ - memset(next,-1,sizeof(next)); - val = 0; - } - } nd[MAXNODE]; - - int root = 0; - int cnt = 0; - - void init(){ - cnt = 0; +#define CHAR_NUM 26 //2--01(异或)字典树,10--只有数字,26--只有大写/小写字母,52--大小写字母都有,62--数字+大小写字母 +#define MAXNODE 500005 +//#define MAXNODE 5000005 //01(异或)字典树的结点数量(必要时候再*2或*10) + + struct node + { + int next[CHAR_NUM]; + int val; + bool flag; //字符串结束标记 + void init() + { + memset(next,-1,sizeof(next)); + val = 0; + flag = false; + } + } nd[MAXNODE]; + + int root; + int cnt; + + void init() + { + cnt = 0; root = newnode(); } - int newnode(){ - nd[cnt].init(); - return cnt++; - } + int newnode() + { + nd[cnt].init(); + return cnt++; + } - void insert(char *s){ + void insert(char *s) + { int temp = root; - for(int i = 0;s[i];i++){ - int pos = s[i]-'a'; + for(int i = 0; s[i]; i++) + { + int pos = s[i] - 'a'; + //int pos = s[i] - '0'; if(nd[temp].next[pos]==-1) nd[temp].next[pos] = newnode(); temp = nd[temp].next[pos]; nd[temp].val++; } + nd[temp].flag = true; } - int find(char *s){ + int find(char *s) + { int temp = root; - for(int i = 0;s[i];i++){ - int pos = s[i]-'a'; - if(nd[temp].next[pos]==-1){ + for(int i = 0; s[i]; i++) + { + int pos = s[i] - 'a'; + //int pos = s[i] - '0'; + if(nd[temp].next[pos]==-1) + { return 0; - }else + } + else temp = nd[temp].next[pos]; } return nd[temp].val; } + + /*以下为01(异或)字典树需要增加的操作(用query函数替代find函数)*/ + /*求与给定数异或的最大值,不要把0插入字典树*/ + /*求与给定数异或的最大值,不要把0插入字典树*/ + /*求一段区间的最大(小)异或值和,类似前缀和的形式预处理:sum[i] ^= sum[i-1] + 一段区间[l,r]的异或值就等于:sum[r]^sum[l-1] + 然后问题就转化成了求区间两端的数 + 注意要先把0插入字典树 + */ + + //转换函数(十进制转换为二进制) + void trans(char *s, int val) //val为需要转换的十进制值 + { + memset(s,0,sizeof(s)); + for(int i=DIGIT_NUM-1; i>=0; i--) //从高位往低位考虑 + s[i] = ((val >> i) & 1) + '0'; + reverse(s,s+DIGIT_NUM-1); + s[DIGIT_NUM] = '\0'; + } + + //查询最大(小)值函数 + //如果要求最大值,就尽量往反方向走(如果是0,就往1走,如果是1,就往0走) + //如果要求最小值,就尽量往同方向走(如果是0,就往0走,如果是1,就往1走) + int query(char *s, int val, int flag) //val为要参与运算的数值(或预处理求出的某个前缀和),flag为求最大(小)值标记 + { + int temp = root; + for(int i = 0; s[i]; i++) + { + int pos = s[i] - '0'; + pos ^= flag; //求最大值时设定flag=1,实现往反方向走;求最小值时设定flag=0,实现往同方向走 + if(nd[temp].next[pos]==-1) + pos ^= 1; //找最后一个的时候要去掉自己本身 + temp = nd[temp].next[pos]; + } + return nd[temp].val ^ val; //sum[r-l] = sum[r] ^ sum[l-1]; + } } trie; diff --git "a/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/DLX(\347\262\276\347\241\256\350\246\206\347\233\226).cpp" "b/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/DLX(\347\262\276\347\241\256\350\246\206\347\233\226).cpp" deleted file mode 100644 index a339744..0000000 --- "a/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/DLX(\347\262\276\347\241\256\350\246\206\347\233\226).cpp" +++ /dev/null @@ -1,99 +0,0 @@ -class DLX{ -public: - int m,sz;//列数,结点数 - int S[MAXN];//每列结点数 - - int row[MAXNODE],col[MAXNODE]; - int L[MAXNODE],R[MAXNODE],U[MAXNODE],D[MAXNODE]; - - int ansd,ans[MAXN]; - - void init(int m){ - this->m = m; - - for(int i = 0;i<=m;i++){ - U[i] = i,D[i] = i,L[i] = i-1,R[i] = i+1; - col[i] = i; - } - R[m] = 0,L[0] = m; - - sz = m+1; - memset(S,0,sizeof(S)); - } - - void addRow(int r,vector& columns){ - int first = sz; - for(int i = 0;i<(int)columns.size();i++){ - int c = columns[i]; - L[sz] = sz-1;R[sz] = sz+1;D[sz] = c;U[sz] = U[c]; - D[U[c]] = sz;U[c] = sz; - row[sz] = r;col[sz] = c; - S[c]++;sz++; - } - R[sz-1] = first;L[first] = sz-1; - } - - #define REP(i,A,s) for(int i = A[s];i!=s;i = A[i]) - - void removeNode(int c){ - L[R[c]] = L[c]; - R[L[c]] = R[c]; - } - - //删除列 - void removeCol(int c){ - removeNode(c); - REP(i,D,c) removeRow(i); - } - - void restoreNode(int c){ - L[R[c]] = c; - R[L[c]] = c; - } - - //恢复列 - void restoreCol(int c){ - REP(i,U,c) restoreRow(i); - restoreNode(c); - } - - void removeRow(int r){ - REP(j,R,r){ - U[D[j]] = U[j];D[U[j]] = D[j];--S[col[j]]; - } - } - - void restoreRow(int r){ - REP(j,L,r){ - ++S[col[j]];U[D[j]] = j;D[U[j]] = j; - } - } - - int ret; - int vis[MAXN]; - - void dfs(int d,int cost){ - if(cost>=ret) return; - if(R[0]==0){ - ret = cost; - return; - } - - //找S最小的列来删除加速 - int c = R[0]; - REP(i,R,0) if(S[i]m = m; - - for(int i = 0;i<=m;i++){ - U[i] = i,D[i] = i,L[i] = i-1,R[i] = i+1; - col[i] = i; - } - R[m] = 0,L[0] = m; - - sz = m+1; - memset(S,0,sizeof(S)); - } - - //行列都是从1开始标号 - void addRow(int r,vector& columns){ - int first = sz; - for(int i = 0;i<(int)columns.size();i++){ - int c = columns[i]; - L[sz] = sz-1;R[sz] = sz+1;D[sz] = c;U[sz] = U[c]; - D[U[c]] = sz;U[c] = sz; - row[sz] = r;col[sz] = c; - S[c]++;sz++; - } - R[sz-1] = first;L[first] = sz-1; - } - -#define REP(i,A,s) for(int i = A[s];i!=s;i = A[i]) - - void removeNode(int c){ - L[R[c]] = L[c]; - R[L[c]] = R[c]; - --S[col[c]]; - } - - //删除列 - void removeCol(int c){ - REP(i,D,c) removeNode(i); - } - - void restoreNode(int c){ - ++S[col[c]]; - L[R[c]] = c; - R[L[c]] = c; - } - - //恢复列 - void restoreCol(int c){ - REP(i,U,c) restoreNode(i); - } - - void removeRow(int r){ - REP(j,R,r){ - U[D[j]] = U[j];D[U[j]] = D[j];--S[col[j]]; - } - } - - void restoreRow(int r){ - REP(j,L,r){ - ++S[col[j]];U[D[j]] = j;D[U[j]] = j; - } - } - - int ret; - int vis[MAXN]; - - int h(){ - memset(vis, 0, sizeof(vis)); - int res = 0; - REP(i,R,0){ - if (vis[col[i]]) continue; - vis[col[i]] = 1; - ++res; - REP(j,D,i){ - if(col[j]) - REP(k,R,j) vis[col[k]] = 1; - } - } - return res; - } - - - bool dfs(int d,int cost){ - if(cost+h()>k) return false; - if(R[0]==0) return true; - - //找S最小的列来删除加速 - int c = R[0]; - REP(i,R,0) if(S[i] m = m; + // + for(int i = 0; i <= m; i++) + { + U[i] = i, D[i] = i, L[i] = i - 1, R[i] = i + 1; + col[i] = i; + } + R[m] = 0, L[0] = m; + sz = m + 1; + memset(nds, 0, sizeof(nds)); + } + + void addRow(int r, vector& columns) + { + int first = sz; + for(int i = 0; i < (int)columns.size(); i++) + { + int c = columns[i]; + L[sz] = sz - 1; + R[sz] = sz + 1; + D[sz] = c; + U[sz] = U[c]; + D[U[c]] = sz; + U[c] = sz; + row[sz] = r; + col[sz] = c; + nds[c]++; + sz++; + } + R[sz - 1] = first; + L[first] = sz - 1; + } + + void removeNode(int c) + { + L[R[c]] = L[c]; + R[L[c]] = R[c]; + } + + //ɾ + void removeCol(int c) + { + removeNode(c); + for(int i = D[c]; i != c; i = D[i]) + removeRow(i); + } + + void restoreNode(int c) + { + L[R[c]] = c; + R[L[c]] = c; + } + + //ָ + void restoreCol(int c) + { + for(int i = U[c]; i != c; i = U[i]) + restoreRow(i); + restoreNode(c); + } + + void removeRow(int r) + { + for(int j = R[r]; j != r; j = R[j]) + { + U[D[j]] = U[j]; + D[U[j]] = D[j]; + --nds[col[j]]; + } + } + + void restoreRow(int r) + { + for(int j = L[r]; j != r; j = L[j]) + { + ++nds[col[j]]; + U[D[j]] = j; + D[U[j]] = j; + } + } + + bool dfs(int d) + { + if(R[0] == 0) //ҵ + { + ansd = d; + return true; + } + //SСɾ + int c = R[0]; // һδɾ + for(int i = R[0]; i != 0; i = R[i]) + { + if(nds[i] < nds[c]) + c = i; + } + removeCol(c); //ɾc + for(int i = D[c]; i != c; i = D[i]) //ýiиǵc + { + ans[d] = row[i]; + for(int j = R[i]; j != i; j = R[j]) //ɾiܸǵ + removeCol(col[j]); + if(dfs(d + 1)) + return true; + for(int j = L[i]; j != i; j = L[j]) //ָiܸǵ + restoreCol(col[j]); + } + restoreCol(c); //ָc + return false; + } + + int solve(char *str) + { + init(9 * 9 + (3 * 9) * 9); //9*9ľŹÿֻһ + 9993*3ÿһֶֻ11~9 + for(int i = 0; i < 9; i++) + { + for(int j = 0; j < 9; j++) + { + int idx = i * 9 + j; //ÿַе± + if(str[idx] != '.') //øѾ + { + int num = str[idx] - '0'; + vector v; + v.PB(i * 9 + j + 1); //iеjֻһ + v.PB(9 * 9 + i * 9 + num); //iѾnum + v.PB(9 * 9 * 2 + j * 9 + num); //jѾnum + v.PB(9 * 9 * 3 + (i / 3 * 3 + j / 3) * 9 + num); //(i/3*3+j/3)3*3ĸѾnum + addRow(9 * 9 * i + 9 * j + num, v); + } + else //øδ + { + for(int num = 1; num <= 9; num++) + { + vector v; + v.PB(i * 9 + j + 1); //iеjֻһ + v.PB(9 * 9 + i * 9 + num); //iѾnum + v.PB(9 * 9 * 2 + j * 9 + num); //jѾnum + v.PB(9 * 9 * 3 + (i / 3 * 3 + j / 3) * 9 + num); //(i/3*3+j/3)3*3ĸѾnum + addRow(9 * 9 * i + 9 * j + num, v); + } + } + } + } + dfs(0); + int sud[10][10]; + for(int i = 0; i < ansd; i++) + { + int tmp = ans[i]; + tmp--; + int val = tmp % 9 + 1; + tmp /= 9; + int c = tmp % 9; + tmp /= 9; + int r = tmp; + sud[r][c] = val; + } + for(int i = 0; i < 9; i++) + { + for(int j = 0; j < 9; j++) + printf("%d", sud[i][j]); + puts(""); + } + } +} dlx; diff --git "a/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/DLX\357\274\210\347\262\276\347\241\256\350\246\206\347\233\226\357\274\211.cpp" "b/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/DLX\357\274\210\347\262\276\347\241\256\350\246\206\347\233\226\357\274\211.cpp" new file mode 100644 index 0000000..3762950 --- /dev/null +++ "b/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/DLX\357\274\210\347\262\276\347\241\256\350\246\206\347\233\226\357\274\211.cpp" @@ -0,0 +1,135 @@ + +//行编号从1开始,列编号为1~n,结点0是表头结点; 结点1~n是各列顶部的虚拟结点 + +class DLX +{ +public: + int m, sz; //列数,结点数 + int S[MAXN]; //每列结点数 + + int row[MAXNODE], col[MAXNODE]; //row/col数组用来记录某个标号的结点在矩阵中的行号和列号 + int L[MAXNODE], R[MAXNODE], U[MAXNODE], D[MAXNODE]; //U/D/R/L数组用来记录某个标号的结点的上下左右结点的编号(十字链表) + + int ansd, ans[MAXM]; //解的数量和解 + + void init(int m) //m为列数 + { + this -> m = m; + //虚拟结点 + for(int i = 0; i <= m; i++) + { + U[i] = i, D[i] = i, L[i] = i - 1, R[i] = i + 1; + col[i] = i; + } + R[m] = 0, L[0] = m; + sz = m + 1; + memset(S, 0, sizeof(S)); + } + + void addRow(int r, vector& columns) + { + int first = sz; + for(int i = 0; i < (int)columns.size(); i++) + { + int c = columns[i]; + L[sz] = sz - 1; + R[sz] = sz + 1; + D[sz] = c; + U[sz] = U[c]; + D[U[c]] = sz; + U[c] = sz; + row[sz] = r; + col[sz] = c; + S[c]++; + sz++; + } + R[sz - 1] = first; + L[first] = sz - 1; + } + + void removeNode(int c) + { + L[R[c]] = L[c]; + R[L[c]] = R[c]; + } + + //删除列 + void removeCol(int c) + { + removeNode(c); + for(int i = D[c]; i != c; i = D[i]) + removeRow(i); + } + + void restoreNode(int c) + { + L[R[c]] = c; + R[L[c]] = c; + } + + //恢复列 + void restoreCol(int c) + { + for(int i = U[c]; i != c; i = U[i]) + restoreRow(i); + restoreNode(c); + } + + void removeRow(int r) + { + for(int j = R[r]; j != r; j = R[j]) + { + U[D[j]] = U[j]; + D[U[j]] = D[j]; + --S[col[j]]; + } + } + + void restoreRow(int r) + { + for(int j = L[r]; j != r; j = L[j]) + { + ++S[col[j]]; + U[D[j]] = j; + D[U[j]] = j; + } + } + + + int ret; + int vis[MAXN]; + + void dfs(int d, int cost) + { + if(R[0] == 0) + { + ret = cost; + return; + } + //找S最小的列来删除加速 + int c = R[0]; + for(int i = R[0]; i != 0; i = R[i]) + { + if(S[i] < S[c]) + c = i; + } + removeCol(c); + for(int i = D[c]; i != c; i = D[i]) + { + ans[d] = row[i]; //记录解 + for(int j = R[i]; j != i; j = R[j]) + removeCol(col[j]); + dfs(d + 1, cost + ::c[row[i] - 1]); + for(int j = L[i]; j != i; j = L[j]) + restoreCol(col[j]); + } + restoreCol(c); + } + + int solve() + { + ret = INF; + dfs(0, 0); + return ret; + } +} dlx; diff --git "a/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/DLX\357\274\210\351\207\215\345\244\215\350\246\206\347\233\226\357\274\211.cpp" "b/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/DLX\357\274\210\351\207\215\345\244\215\350\246\206\347\233\226\357\274\211.cpp" new file mode 100644 index 0000000..fddaced --- /dev/null +++ "b/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/DLX\357\274\210\351\207\215\345\244\215\350\246\206\347\233\226\357\274\211.cpp" @@ -0,0 +1,146 @@ + +class DLX +{ +public: + int m, sz; //列数,结点数 + int S[MAXN]; //每列结点数 + + int row[MAXNODE], col[MAXNODE]; //row/col数组用来记录某个标号的结点在矩阵中的行号和列号 + int L[MAXNODE], R[MAXNODE], U[MAXNODE], D[MAXNODE]; //U/D/R/L数组用来记录某个标号的结点的上下左右结点的编号(十字链表) + + int ansd, ans[MAXN]; //解的数量和解 + + void init(int m) //m为列数 + { + this -> m = m; + //虚拟结点 + for(int i = 0; i <= m; i++) + { + U[i] = i, D[i] = i, L[i] = i - 1, R[i] = i + 1; + col[i] = i; + } + R[m] = 0, L[0] = m; + sz = m + 1; + memset(S, 0, sizeof(S)); + } + + //行列都是从1开始标号 + void addRow(int r, vector& columns) + { + int first = sz; + for(int i = 0; i < (int)columns.size(); i++) + { + int c = columns[i]; + L[sz] = sz - 1; + R[sz] = sz + 1; + D[sz] = c; + U[sz] = U[c]; + D[U[c]] = sz; + U[c] = sz; + row[sz] = r; + col[sz] = c; + S[c]++; + sz++; + } + R[sz - 1] = first; + L[first] = sz - 1; + } + + void removeNode(int c) + { + L[R[c]] = L[c]; + R[L[c]] = R[c]; + --S[col[c]]; + } + + //删除列 + void removeCol(int c) + { + for(int i = D[c]; i != c; i = D[i]) + removeNode(i); + } + + void restoreNode(int c) + { + ++S[col[c]]; + L[R[c]] = c; + R[L[c]] = c; + } + + //恢复列 + void restoreCol(int c) + { + for(int i = U[c]; i != c; i = U[i]) + restoreNode(i); + } + + int ret; + int vis[MAXN]; + + int h() //估价函数:模拟删除列,函数返回的是至少还需要多少行才能完成重复覆盖 + { + memset(vis, 0, sizeof(vis)); + int res = 0; + for(int i = R[0]; i != 0; i = R[i]) + { + if(vis[col[i]]) + continue; + vis[col[i]] = 1; + ++res; + for(int j = D[i]; j != i; j = D[j]) + { + if(col[j]) + { + for(int k = R[j]; k != j; k = R[k]) + vis[col[k]] = 1; + } + } + } + return res; + } + + bool dfs(int d, int cost) + { + if(cost + h() > k) + return false; + if(R[0] == 0) + { + //ansd = min(ansd, d); + return true; + } + //找S最小的列来删除加速 + int c = R[0]; + for(int i = R[0]; i != 0; i = R[i]) + { + if(S[i] < S[c]) + c = i; + } + for(int i = D[c]; i != c; i = D[i]) + { + //ans[d] = row[i]; //记录解 + removeCol(i); + for(int j = R[i]; j != i; j = R[j]) + removeCol(j); + if(dfs(d + 1, cost + 1)) + return true; + for(int j = L[i]; j != i; j = L[j]) + restoreCol(j); + restoreCol(i); + } + return false; + } + + void solve() + { + for(ansd = 0; ansd <= m; ansd++) + { + if(dfs(0, 0)) + break; + } + /* + ansd = INF; + dfs(0, 0); + */ + printf("%d\n", ansd); + } +} dlx; diff --git "a/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/dfs\345\272\217.cpp" "b/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/dfs\345\272\217.cpp" new file mode 100644 index 0000000..17f4073 --- /dev/null +++ "b/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/dfs\345\272\217.cpp" @@ -0,0 +1,44 @@ +//dfs序模板 + +#define MAXN 100005 +#define MAXE 100005 + + +struct Edge +{ + int v,nxt; + Edge() {} + Edge(int v,int nxt):v(v),nxt(nxt) {} +} e[MAXE<<1]; + +int head[MAXN]; +int cnt; + +void addEdge(int u,int v) +{ + e[cnt].v = v; + e[cnt].nxt = head[u]; + head[u] = cnt++; +} + +int dfs_clock; //dfs序时间戳 +int lnd[MAXN],rnd[MAXN]; //为每一个结点赋一个左值lnd和一个右值rnd,这个区间表示这个结点的管辖结点范围。 + +void init() +{ + memset(head,-1,sizeof(head)); + cnt = 0; + dfs_clock = 0; +} + +void dfs(int u,int fa) //dfs序 +{ + lnd[u] = ++dfs_clock; //记录dfs序下该结点被访问的起始时间戳 + for(int i=head[u]; ~i; i=e[i].nxt) + { + int v = e[i].v; + if(v != fa) + dfs(v,u); + } + rnd[u] = dfs_clock; //记录dfs序下该结点被访问的结束时间戳 +} diff --git "a/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/\344\270\211\345\210\206\346\237\245\346\211\276.cpp" "b/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/\344\270\211\345\210\206\346\237\245\346\211\276.cpp" new file mode 100644 index 0000000..55726d3 --- /dev/null +++ "b/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/\344\270\211\345\210\206\346\237\245\346\211\276.cpp" @@ -0,0 +1,25 @@ + +/* +三分查找主要用来求凸性的函数的极值(最大值/最小值) +精度设置为EPS=1e-9以上不容易WA +*/ + +typedef double Type; + +Type cal(Type val) +{ + /*这里根据凸性函数的表达式进行计算*/ +} + +pair ternarySearch(Type l,Type r) //三分函数 +{ + while(r - l >= EPS) + { + double lmid = (l + r) / 2.0, rmid = (lmid + r) / 2.0; + if(cal(lmid) >= cal(rmid)) + r = rmid; + else + l = lmid; + } + return MP(l,cal(l)); //返回函数的x值和y值 +} diff --git "a/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/\344\272\214\345\210\206\346\237\245\346\211\276.cpp" "b/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/\344\272\214\345\210\206\346\237\245\346\211\276.cpp" new file mode 100644 index 0000000..4726d62 --- /dev/null +++ "b/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/\344\272\214\345\210\206\346\237\245\346\211\276.cpp" @@ -0,0 +1,42 @@ + +typedef int Type; + +Type cal(Type val) +{ + /*这里写相关函数的表达式*/ +} + +//对于整数 +Type biSearch(Type l,Type r,Type val) +{ + Type ans = -1; + while(l <= r) //对于整数 + { + Type mid = (l + r) >> 1; //对于整数 + if(cal(mid) < val) //对于左边界能取到,右边界不能取到 + //if(cal(mid) <= val) //对于右边界能取到,左边界不能取到 + { + ans = mid; + l = mid + 1; + } + else + r = mid - 1; + } + return ans; +} + +//对于浮点数 +Type biSearch(Type l,Type r,Type val) +{ + while(r - l >= EPS) //对于浮点数 + { + Type mid = (l + r) / 2.0; //对于浮点数 + if(cal(mid) < val) //对于左边界能取到,右边界不能取到 + //if(cal(mid) <= val) //对于右边界能取到,左边界不能取到 + l = mid; + else + r = mid; + } + return l; //对于左边界能取到,右边界不能取到 + //return r; //对于右边界能取到,左边界不能取到 +} diff --git "a/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/\345\220\257\345\217\221\345\274\217\346\220\234\347\264\242A_Star.cpp" "b/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/\345\220\257\345\217\221\345\274\217\346\220\234\347\264\242A_Star.cpp" new file mode 100644 index 0000000..805bb02 --- /dev/null +++ "b/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/\345\220\257\345\217\221\345\274\217\346\220\234\347\264\242A_Star.cpp" @@ -0,0 +1,90 @@ +//启发式搜索A*算法 + +/* + * A*算法是dijkstra最短路算法和BFS的结合 + * 公式:f(n) = g(n) + h(n) + * g(n)代表起点到任意一个结点n的移动耗费 + * h(n)为结点n到终点的估价值,这个估价值可以用曼哈顿估价函数或欧几里得函数来计算 + * * 曼哈顿函数 = |终点ex - 当前点x| + |终点ey - 当前点y| * 10 + * * 欧几里得函数 = sqrt((终点ex - 当前点x) * (终点ex - 当前点x) + (终点ey - 当前点y) * (终点ey - 当前点y)) * 10 + * BFS是h(n) = 0的A*算法,并没有用到启发式; + * Dijkstra算法是g(n) = 0的A*算法,从起点到终点用启发式; + * 两者结合在一起就是A*算法。 + * 估价函数很明显我们选择最小的,所以用优先队列来维护最小值,每次取最优解,一直迭代直到到达目标。 +*/ + +#define MAXN 305 + +struct Node +{ + int x,y; + int step; + int g,h,f; + bool operator <(const Node &a) const + { + return f>a.f; + } +}; + +bool vis[MAXN][MAXN]; +int dx[]={1,-1,-2,-2,-1,1,2,2}; +int dy[]={-2,-2,-1,1,2,2,1,-1}; +int sx,sy; +int ex,ey; +int n; +int ans; + +bool inMap(int x,int y) +{ + if(x>=0 && x=0 && y0?x:-x; +} + +int getH(const Node &a) //启发式函数h() +{ + return (int)sqrt((a.x - ex) * (a.x - ex) + (a.y - ey) * (a.y - ey)) * 10; //使用欧氏距离估值 + //return Abs(a.x - ex) + Abs(a.y - ey) * 10; //使用曼哈顿距离估值 +} + +void Astar() //A*算法 +{ + priority_queue pq; + Node cur,nxt; + cur.x = sx, cur.y = sy; + cur.g = cur.step = 0; + cur.h = getH(cur); + cur.f = cur.g + cur.h; + pq.push(cur); + vis[sx][sy] = true; + while(!pq.empty()) + { + cur = pq.top(); + pq.pop(); + if(cur.x==ex && cur.y==ey) + { + ans = cur.step; + return; + } + for(int i=0; i<8; i++) + { + nxt.x = cur.x + dx[i]; + nxt.y = cur.y + dy[i]; + if(inMap(nxt.x,nxt.y) && !vis[nxt.x][nxt.y]) + { + nxt.step = cur.step + 1; + nxt.g = cur.g + (len) * 10; //(len)为走一步的距离 + //nxt.g = cur.g + ceil((len) * 10); //向上取整 + nxt.h = getH(nxt); + nxt.f = nxt.g + nxt.h; + vis[nxt.x][nxt.y] = true; + pq.push(nxt); + } + } + } +} diff --git "a/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/\346\225\260\344\275\215dp\357\274\210\346\225\260\344\275\215\347\273\237\350\256\241\357\274\211.cpp" "b/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/\346\225\260\344\275\215dp\357\274\210\346\225\260\344\275\215\347\273\237\350\256\241\357\274\211.cpp" new file mode 100644 index 0000000..2b4e448 --- /dev/null +++ "b/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/\346\225\260\344\275\215dp\357\274\210\346\225\260\344\275\215\347\273\237\350\256\241\357\274\211.cpp" @@ -0,0 +1,57 @@ +//数位dp(数位统计)模板 + +//pos = 当前处理的位置(一般从高位到低位) +//pre = 上一个位的数字(更高的那一位) +//s = 要达到的状态,如果为1则可以认为找到了答案,到时候用来返回,给计数器+1。 +//lim = 是否受限,也即当前处理这位能否随便取值。 +//例如567:当前处理6这位。如果前面取的是4,则当前这位可以取0-9; +// 如果前面取的5,那么当前这位就不能随便取,不然会超出这个数的范围。 +// 所以如果前面取5的话此时的lim=1,也就是说当前只可以取0-6。 +//用dp数组保存这三个状态是因为往后转移的时候会遇到很多重复的情况。 + +//a[i]是记录数位的数组 + +//dp[i][0/1]表示当前第i位,前一位是否是某个数X的状态。是的话值为1,否则为0 + +typedef int Type; + +Type dfs(int pos, int s, bool lim) +{ + if(pos == -1) + return 1; + if(!lim && ~dp[pos][s]) + return dp[pos][s]; + Type ret = 0; + int u = lim ? a[pos] : 9; + for(int i = first ? 1 : 0; i <= u; i++) //first是否是最高位。有的题目条件不允许前导零,所以如果前面位已经有1可以任意放,没有1则不能。 + ret += dfs(pos-1, i==6, lim&&i==u); + return lim ? ret : dp[pos][s] = ret; +} + + +Type dfs(int pos,int pre,int s,bool lim) +{ + //已经搜到尽头,返回“是否找到了答案”这个状态 + if(pos == -1) + return 1; + + //dp里保存的是完整的,即不受限的答案。所以如果满足的话,可以直接返回。 + if(!lim && ~dp[pos][pre][s]) //即dp[pos][pre][s] != -1 + return dp[pos][pre][s]; + + int u = lim ? a[pos] : 9; //是否受上一位(高位)数字的限制,u为本位数字的上限 + Type ret = 0; + + //往下搜的状态表示的很巧妙,s用||是因为如果前面找到了答案那么后面还有没有答案都无所谓了。而lim用&&是因为只有前面受限、当前受限才能推出下一步也受限。 + //比如567:如果是46X的情况,虽然6已经到尽头,但是后面的个位仍然可以随便取,因为百位没受限。所以如果个位要受限,那么前面必须是56。 + + //这里用"不要49"一题来做例子。 + for(int i = first ? 1 : 0; i <= u; i++) //first是否是最高位。有的题目条件不允许前导零,所以如果前面位已经有1可以任意放,没有1则不能。 + ret += dfs(pos-1, i, s||(pre==4&&i==9), lim&&(i==u)); + + //dp里保存完整的、取到尽头的数据 + return lim ? ret : dp[pos][pre][s] = ret; +} + + +//PS: __builtin_popcount()是一个GCC的内建函数,能精确计算二进制数中1的个数... 慎用,毕竟不确定比赛的时候编译器是否支持... diff --git "a/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/\346\234\200\351\225\277\344\270\212\345\215\207\345\255\220\345\272\217\345\210\227\357\274\210LIS\357\274\211.cpp" "b/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/\346\234\200\351\225\277\344\270\212\345\215\207\345\255\220\345\272\217\345\210\227\357\274\210LIS\357\274\211.cpp" new file mode 100644 index 0000000..5076013 --- /dev/null +++ "b/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/\346\234\200\351\225\277\344\270\212\345\215\207\345\255\220\345\272\217\345\210\227\357\274\210LIS\357\274\211.cpp" @@ -0,0 +1,12 @@ + +int a[MAXN]; +int dp[MAXN]; + +void LIS() +{ + fill(dp, dp + n,INF); + for(int i = 0; i < n; i++) + *lower_bound(dp, dp + n, a[i]) = a[i]; //最长上升子序列 + //*upper_bound(dp, dp + n, a[i]) = a[i]; //最长不下降子序列 + printf("%d\n", lower_bound(dp, dp + n, INF) - dp); +} diff --git "a/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/\346\240\221\347\232\204\347\233\264\345\276\204\357\274\210\344\270\244\346\254\241dfs+\346\240\221\345\275\242dp\357\274\211.cpp" "b/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/\346\240\221\347\232\204\347\233\264\345\276\204\357\274\210\344\270\244\346\254\241dfs+\346\240\221\345\275\242dp\357\274\211.cpp" new file mode 100644 index 0000000..34b610c --- /dev/null +++ "b/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/\346\240\221\347\232\204\347\233\264\345\276\204\357\274\210\344\270\244\346\254\241dfs+\346\240\221\345\275\242dp\357\274\211.cpp" @@ -0,0 +1,87 @@ + +//建边的时候要建双向边! + +/*方法一:两次dfs*/ + +#define MAXN 50010 + +int d[MAXN]; //d[i]表示以某个结点为根,结点i的深度 +int rt; //第一次dfs后找到的距离临时根结点(1号结点)最远的结点编号,即树的直径的一个端点 + +void dfs(int u, int fa) +{ + for(int i = head[u]; ~i; i = e[i].nxt) + { + int v = e[i].to; + int w = e[i].cost; + if(v != fa) + { + d[v] = d[u] + w; + if(d[v] > d[rt]) //更新距离临时根结点(1号结点)最远的结点编号 + rt = v; + dfs(v, u); + } + } +} + +void solve() //dfs求树的直径 +{ + /*建图等部分代码省略*/ + memset(d, 0, sizeof(d)); + dfs(1, 0); //从临时根节点开始遍历找到最远端的结点即为树的直径的一个端点 + memset(d, 0, sizeof(d)); + dfs(rt, 0); //从该端点开始遍历找到树的直径的另一个端点 + printf("%d\n", d[rt]); +} + + +/*方法二:树形dp*/ + +#define MAXN 50010 + +//模板一 +int dp[MAXN]; //dp[i]表示从节点i出发,往以i为根的子树遍历能够到达的最远距离 +int ans; + +void dfs(int u, int fa) +{ + for(int i = head[u]; ~i; i = e[i].nxt) + { + int v = e[i].to; + int w = e[i].cost; + if(v != fa) + { + dfs(v, u); + ans = max(ans, dp[u] + dp[v] + w); //先用dp[u]更新ans + dp[u] = max(dp[u], dp[v] + w); //再用dp[v]更新dp[u],顺序不能改变 + } + } +} + + +//模板二 + +int dp[MAXN][2]; //dp[i][0/1]表示以i点为树根(从i点出发)能到最远儿子的距离和到次远儿子的距离 + +void dfs(int u, int fa) +{ + dp[u][0] = dp[u][1] = 0; + for(int i = head[u]; ~i; i = e[i].nxt) + { + int v = e[i].to; + int w = e[i].cost; + if(v != fa) + { + dfs(v, u); + if(dp[u][0] < dp[v][0] + w) //更新到最远儿子的距离 + { + dp[u][1] = dp[u][0]; //到最远儿子的距离更新为到次远儿子的距离 + dp[u][0] = dp[v][0] + w; + } + else if(dp[u][1] < dp[v][0] + w) //到最远儿子的距离不需要更新,只需要更新到次远儿子的距离 + dp[u][1] = dp[v][0] + w; + } + } + //到最远儿子的距离 + 到次远儿子的距离 = 树的直径 + ans = max(ans, dp[u][0] + dp[u][1]); //更新最大值 +} diff --git "a/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/\346\240\221\347\232\204\351\207\215\345\277\203\357\274\210\346\240\221\345\275\242dp\357\274\211.cpp" "b/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/\346\240\221\347\232\204\351\207\215\345\277\203\357\274\210\346\240\221\345\275\242dp\357\274\211.cpp" new file mode 100644 index 0000000..68b7af3 --- /dev/null +++ "b/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/\346\240\221\347\232\204\351\207\215\345\277\203\357\274\210\346\240\221\345\275\242dp\357\274\211.cpp" @@ -0,0 +1,26 @@ + +//建边的时候要建双向边! +#define MAXN 50010 + +int sz[MAXN]; //以每个结点为根子树的结点数(包含自身) +int dp[MAXN]; //dp[i]表示沿树路径到第i个点时子树结点数的最大值(不含自身) +int nodecnt; //当前子树中所有结点数 +int rt; //求得当前子树的重心 + +void dfs(int u, int fa) +{ + dp[u] = 0, sz[u] = 1; + for(int i = head[u]; ~i; i = e[i].nxt) + { + int v = e[i].to; + if(v != fa) + { + dfs(v, u); + sz[u] += sz[v]; + dp[u] = max(dp[u], sz[v]); + } + } + dp[u] = max(dp[u], nodecnt - sz[u]); //树的重心的定义:以该点为根的有根树,最大子树的结点数最小 + if(dp[u] < dp[rt]) + rt = u; +} diff --git "a/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/\350\203\214\345\214\205\351\227\256\351\242\230\357\274\210dp\357\274\211.cpp" "b/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/\350\203\214\345\214\205\351\227\256\351\242\230\357\274\210dp\357\274\211.cpp" new file mode 100644 index 0000000..29a2b3d --- /dev/null +++ "b/\345\270\270\347\224\250\345\260\217\347\256\227\346\263\225\346\261\207\346\200\273/\350\203\214\345\214\205\351\227\256\351\242\230\357\274\210dp\357\274\211.cpp" @@ -0,0 +1,40 @@ +#define MAXN 105 +#define MAXM 100005 + +int w[MAXN],cnt[MAXN]; +int dp[MAXM]; +int n,m; + +void ZeroOnePack(int value,int weight) //01背包 +{ + for(int i=m; i>=weight; i--) + { + dp[i]=max(dp[i],dp[i-weight]+value); + } +} + +void CompletePack(int value,int weight) //完全背包 +{ + for(int i=weight; i<=m; i++) + { + dp[i]=max(dp[i],dp[i-weight]+value); + } +} + +void MultiPack(int value,int weight,int cnt) +{ + if(weight*cnt>=m) //转化为完全背包 + CompletePack(value,weight); + else //转化为01背包 + { + int k=1; + while(k<=cnt) //二进制优化 + { + ZeroOnePack(value*k,weight*k); + cnt-=k; + k*=2; + } + for(int i=m; i>=cnt*weight; i--) + dp[i]=max(dp[i],dp[i-cnt*weight]+cnt*value); + } +} \ No newline at end of file diff --git "a/\346\225\260\345\255\246/Miller_Robin\347\264\240\346\200\247\346\265\213\350\257\225+Pollard_rho\345\244\247\346\225\260\345\233\240\346\225\260\345\210\206\350\247\243.cpp" "b/\346\225\260\345\255\246/Miller_Robin\347\264\240\346\200\247\346\265\213\350\257\225+Pollard_rho\345\244\247\346\225\260\345\233\240\346\225\260\345\210\206\350\247\243.cpp" new file mode 100644 index 0000000..edae196 --- /dev/null +++ "b/\346\225\260\345\255\246/Miller_Robin\347\264\240\346\200\247\346\265\213\350\257\225+Pollard_rho\345\244\247\346\225\260\345\233\240\346\225\260\345\210\206\350\247\243.cpp" @@ -0,0 +1,150 @@ +//Miller_Rabin素性测试+Pollard_rho大数因数分解 + +typedef long long LL; + +const int S=20; //判断次数(8~12) + +int tol=0; //质因数的个数。数组小标从0开始 +LL factor[100]; //质因数分解结果(刚返回时是无序的) + +/*Miller_Rabin判断大数(2^63)是否是素数*/ +//(a*b)%c +LL mult_mod(LL a,LL b,LL c) +{ + a%=c; + b%=c; + LL ret=0; + while(b) + { + if(b&1) + { + ret+=a; + ret%=c; + } + a<<=1; + if(a>=c) a%=c; + b>>=1; + } + return ret; +} + +//(x^n)%mod +LL pow_mod(LL x,LL n,LL mod) +{ + if(n==1) return x%mod; + x%=mod; + LL ret=1; + LL temp=x; + while(n) + { + if(n&1) ret=mult_mod(ret,temp,mod); + temp=mult_mod(temp,temp,mod); + n>>=1; + } + return ret; +} + +//check a^(n-1)==1(mod n) +bool check(LL a,LL n,LL x,LL t) +{ + LL ret=pow_mod(a,x,n); + LL last=ret; + for(int i=1; i<=t; i++) + { + ret=mult_mod(ret,ret,n); + if(ret==1&&last!=1&&last!=n-1) return true; //二次探测排除Carmichael数 + last=ret; + } + if(ret!=1) return true; + return false; +} + +bool Miller_Rabin(LL n) +{ + if(n<2) return false; + if(n==2) return true; + if((n&1)==0) return false; + LL x=n-1; + LL t=0; + while((x&1)==0) + { + x>>=1; + t++; + } + for(int i=0; i=n) + p=Pollard_rho(p,c--); + findfac(p,k); + findfac(n/p,k); +} + + +//对n进行素因子分解 +void findfac(LL n) +{ + if(Miller_Rabin(n))//素数 + { + factor[tol++]=n; + return; + } + LL p=n; + while(p>=n) + p=Pollard_rho(p,rand()%(n-1)+1); + findfac(p); + findfac(n/p); +} diff --git "a/\346\225\260\345\255\246/\345\237\203\346\260\217\347\255\233\346\261\202\345\217\215\347\264\240\346\225\260\357\274\210\347\272\277\346\200\247\347\255\233\346\261\202\345\217\215\347\264\240\346\225\260\357\274\211.cpp" "b/\346\225\260\345\255\246/\345\237\203\346\260\217\347\255\233\346\261\202\345\217\215\347\264\240\346\225\260\357\274\210\347\272\277\346\200\247\347\255\233\346\261\202\345\217\215\347\264\240\346\225\260\357\274\211.cpp" new file mode 100644 index 0000000..7cc3e3a --- /dev/null +++ "b/\346\225\260\345\255\246/\345\237\203\346\260\217\347\255\233\346\261\202\345\217\215\347\264\240\346\225\260\357\274\210\347\272\277\346\200\247\347\255\233\346\261\202\345\217\215\347\264\240\346\225\260\357\274\211.cpp" @@ -0,0 +1,11 @@ + +int ap[MAXN]; // + +void init() //ʽɸ +{ + for(int i = 1; i < MAXN; i++) + { + for(int j = 1; i * j < MAXN; j++) + ap[i * j]++; + } +} diff --git "a/\346\225\260\345\255\246/\345\277\253\351\200\237\345\271\202.cpp" "b/\346\225\260\345\255\246/\345\277\253\351\200\237\345\271\202.cpp" new file mode 100644 index 0000000..54e0911 --- /dev/null +++ "b/\346\225\260\345\255\246/\345\277\253\351\200\237\345\271\202.cpp" @@ -0,0 +1,29 @@ +//快速幂模板 + +#define long long LL + +//非递归版 +LL quickPow(LL x,LL k,LL mod) +{ + LL res = 1; + while(k > 0) + { + if(k & 1) + res = res * x % mod; + x = x * x % mod; + k >>= 1; + } + return res; +} + + +//递归版 +LL quickPow(LL x,LL k,LL mod) +{ + if(k == 0) + return 1; + LL res = quickPow(x*x%mod,n/2,mod); + if(n & 1) + res = res * x % mod; + return res; +} diff --git "a/\346\225\260\345\255\246/\346\211\251\345\261\225\346\254\247\345\207\240\351\207\214\345\276\227.cpp" "b/\346\225\260\345\255\246/\346\211\251\345\261\225\346\254\247\345\207\240\351\207\214\345\276\227.cpp" new file mode 100644 index 0000000..2e3f51f --- /dev/null +++ "b/\346\225\260\345\255\246/\346\211\251\345\261\225\346\254\247\345\207\240\351\207\214\345\276\227.cpp" @@ -0,0 +1,50 @@ +//《挑战程序设计竞赛》版 +int exgcd(int a,int b,int &x,int &y) +{ + int d=a; + if(b!=0) + { + d=exgcd(b,a%b,y,x); + y-=(a/b)*x; + } + else + { + x=1; + y=0; + } + return d; +} + +//递归版 +int exgcd(int a,int b,int &x,int &y) +{ + if(b==0) + { + x=1; + y=0; + return a; + } + int d=exgcd(b,a%b,x,y); + int t=x; + x=y; + y=t-a/b*y; + return d; +} + +//x,y全局变量版 +int x; +int y; +int exgcd(int a,int b) +{ + if(b==0) + { + x=1; + y=0; + return a; + } + int d=exgcd(b,a%b); + int t=x; + x=y; + y=t-a/b*y; + return d; +} diff --git "a/\346\225\260\345\255\246/\346\254\247\346\213\211\345\207\275\346\225\260.cpp" "b/\346\225\260\345\255\246/\346\254\247\346\213\211\345\207\275\346\225\260.cpp" new file mode 100644 index 0000000..719b485 --- /dev/null +++ "b/\346\225\260\345\255\246/\346\254\247\346\213\211\345\207\275\346\225\260.cpp" @@ -0,0 +1,78 @@ + +/* ijŷֵӶO(sqrt(n)) */ +int getPhi(int x) +{ + int ans = x; + int cnt = sqrt(x + 0.5) + 1; + for(int i = 2; i < cnt; i++) + { + if(x % i == 0) + { + ans -= ans / i; + while(x % i == 0) + x /= i; + } + if(x == 1) + break; + } + if(x > 1) + ans -= ans / x; + return ans; +} + + +/* ɸŷӶO(nlogn) */ +int phi[MAXN]; + +void getEuler() +{ + memset(phi, 0, sizeof(phi)); + phi[1] = 1; + for(int i = 2; i < MAXN; i++) + { + if(!phi[i]) //Ϊ + { + for(int j = i; j < MAXN; j += i) + { + if(!phi[j]) + phi[j] = j; + phi[j] -= phi[j] / i; + } + } + } +} + + +/* ɸŷӶO(n) */ +bool isprime[MAXN]; +int prime[MAXN]; +int phi[MAXN]; +int phicnt; + +void fastEuler() +{ + memset(isprime, true, sizeof(isprime)); + isprime[0] = isprime[1] = false; + phi[1] = 1; + phicnt = 0; + for(int i = 2; i < MAXN; i++) + { + if(isprime[i]) + { + prime[phicnt++] = i; + phi[i] = i - 1; // n = p ^ k p Ϊ phi(n) = p ^ k - p ^ (k - 1) = (p - 1) * p ^ (k - 1) + } + for(int j = 0; j < phicnt; j++) + { + if(i * prime[j] > MAXN) + break; + isprime[i * prime[j]] = false; + if(i % prime[j] == 0) + { + phi[i * prime[j]] = phi[i] * prime[j]; //ŷʽ + break; + } + phi[i * prime[j]] = phi[i] * (prime[j] - 1); + } + } +} diff --git "a/\346\225\260\345\255\246/\347\237\251\351\230\265\346\250\241\350\277\220\347\256\227\357\274\210\346\250\241\345\212\240\346\263\225\343\200\201\346\250\241\344\271\230\346\263\225\343\200\201\345\277\253\351\200\237\345\271\202\343\200\201\346\250\241\345\271\202\345\222\214\357\274\211.cpp" "b/\346\225\260\345\255\246/\347\237\251\351\230\265\346\250\241\350\277\220\347\256\227\357\274\210\346\250\241\345\212\240\346\263\225\343\200\201\346\250\241\344\271\230\346\263\225\343\200\201\345\277\253\351\200\237\345\271\202\343\200\201\346\250\241\345\271\202\345\222\214\357\274\211.cpp" new file mode 100644 index 0000000..1bad6b2 --- /dev/null +++ "b/\346\225\260\345\255\246/\347\237\251\351\230\265\346\250\241\350\277\220\347\256\227\357\274\210\346\250\241\345\212\240\346\263\225\343\200\201\346\250\241\344\271\230\346\263\225\343\200\201\345\277\253\351\200\237\345\271\202\343\200\201\346\250\241\345\271\202\345\222\214\357\274\211.cpp" @@ -0,0 +1,95 @@ + +typedef LL Type; + +const int MAXN = 55; +const LL MOD = 1000000007; + +int n; +Type mod; + +/* 矩阵类 */ +struct Matrix +{ + Type x[MAXN][MAXN]; + void init() + { + memset(x, 0, sizeof(x)); + } + /* 初始化为单位矩阵 */ + void toIdentity() + { + memset(x, 0, sizeof(x)); + for(int i = 0; i < n; i++) + x[i][i] = 1; + } + /* 输出矩阵 */ + void print() + { + for(int i = 0; i < n; i++) + for(int j = 0; j < n; j++) + printf("%lld%c", x[i][j], j == n - 1 ? '\n' : ' '); + } +} A; + +/* 矩阵模乘法 */ +Matrix mul(Matrix a, Matrix b) //(a * b) % mod +{ + Matrix ans; + for(int i = 0; i < n; i++) + { + for(int j = 0; j < n; j++) + { + ans.x[i][j] = 0; + for(int k = 0; k < n; k++) + ans.x[i][j] += a.x[i][k] * b.x[k][j]; + ans.x[i][j] %= mod; + } + } + return ans; +} + +/* 矩阵模加法 */ +Matrix add(Matrix a, Matrix b) //(a + b) % mod +{ + int i, j; + Matrix ans; + for(i = 0; i < n; i++) + { + for(j = 0; j < n; j++) + { + ans.x[i][j] = a.x[i][j] + b.x[i][j]; + ans.x[i][j] %= mod; + } + } + return ans; +} + +/* 矩阵快速幂 */ +Matrix pow(Matrix a, Type k) //(a ^ n) % mod +{ + Matrix ans; + ans.toIdentity(); + while(k) + { + if(k & 1) //k % 2 + ans = mul(ans, a); + k /= 2; + a = mul(a, a); + } + return ans; +} + +/* 矩阵模幂和 */ +Matrix sum(Matrix a, Type k) //(a + a ^ 2 + a ^ 3 + ... + a ^ n) % mod +{ + Type m; + Matrix ans, pre; + if(k == 1) + return a; + m = k / 2; + pre = sum(a, m); //[1, n / 2] + ans = add(pre, mul(pre, pow(a, m))); //ans = [1, n / 2] + a ^ (n / 2) * [1, n / 2] + if(n & 1) + ans = add(ans, pow(a, k)); // ans = ans + a ^ n + return ans; +} diff --git "a/\346\225\260\345\255\246/\347\273\204\345\220\210\346\225\260.cpp" "b/\346\225\260\345\255\246/\347\273\204\345\220\210\346\225\260.cpp" new file mode 100644 index 0000000..dad8eb1 --- /dev/null +++ "b/\346\225\260\345\255\246/\347\273\204\345\220\210\346\225\260.cpp" @@ -0,0 +1,52 @@ + +/* 线性预处理逆元 */ + +LL inv[MAXN]; +LL res[MAXN]; +LL fac[MAXN]; + +void initInv() +{ + inv[1] = 1; + fac[1] = 1; + res[1] = 1; + for(int i = 2; ifabs(a[r][i])) r = j; - if(r!=i) for(int j = 0;j<=n;j++) swap(a[r][j],a[i][j]); - for(int k = i+1;k=0;i--){ - for(int j = i+1;j abs(a[max_r][col])) //记录第一个第col列系数非零的行 + max_r = i; + } + if(a[max_r][col] == 0) + { + k--; + free_x[free_num++] = col; //这个是自由变元 + continue; + } + if(max_r != k) + { + for(int j = col; j < var+1; j++) //将第一个第col列系数非零的行换到第k行 + swap(a[k][j],a[max_r][j]); + } + for(int i = k+1; i < equ; i++) //开始消元 + { + if(a[i][col]) //系数非零 + { + for(int j = col; j < var+1; j++) //从当前第col列开始消元 + a[i][j] ^= a[k][j]; + } + } + } + /*无解*/ + for(int i = k; i < equ; i++) + { + if(a[i][col]) + return -1; + } + /*有无穷多解*/ + if(k < var) // + return var - k; //返回自由变元个数 + /*有唯一解*/ + for(int i = var-1; i >= 0; i--) + { + x[i] = a[i][var]; + for(int j = i+1; j < var; j++) //回代求出解集 + x[i] ^= (a[i][j] && x[j]); + } + return 0; +} + +int solve(int equ, int var) //枚举自由变元 +{ + int res = Gauss_xor(equ,var); + if(res == -1) //无解 + return -1; + else if(res == 0) //唯一解 + { + int ans = 0; + for(int i = 0; i < var; i++) + ans += x[i]; + return ans; + } + else //多解(枚举自由变元) + { + int ans = INF; + for(int i = 0; i < (1<= 0; j--) //从消完元矩阵的主对角线非0的最后一行开始回代 + { + int idx; + for(idx = j; idx < var; idx++) + { + if(a[j][idx]) + break; + } + x[idx] = a[j][var]; + for(int l = idx+1; l < var; l++) //回代求出解集 + { + if(a[j][l]) + x[idx] ^= x[l]; + } + cnt += x[idx]; + } + ans = min(ans,cnt); + } + return ans; + } +} diff --git "a/\346\225\260\345\255\246/\351\253\230\346\226\257\346\266\210\345\205\203\346\263\225\357\274\210\346\225\264\346\225\260\357\274\211.cpp" "b/\346\225\260\345\255\246/\351\253\230\346\226\257\346\266\210\345\205\203\346\263\225\357\274\210\346\225\264\346\225\260\357\274\211.cpp" new file mode 100644 index 0000000..bffe99a --- /dev/null +++ "b/\346\225\260\345\255\246/\351\253\230\346\226\257\346\266\210\345\205\203\346\263\225\357\274\210\346\225\264\346\225\260\357\274\211.cpp" @@ -0,0 +1,123 @@ + +#define MAXN 105 + +int a[MAXN][MAXN]; //增广矩阵 +int x[MAXN]; //解集 +bool free_x[MAXN]; //标记是否是不确定的变元(1为不确定,0为确定) + +/* +void print(int equ, int var) +{ + for(int i = 0; i < equ; i++) + { + for(int j = 0; j < var + 1; j++) + printf("%d ",a[i][j]); + puts(""); + } + puts(""); +} +*/ + +inline int lcm(int a,int b) +{ + return a / __gcd(a,b) * b; //先除后乘防止溢出 +} + +/* +返回-2表示有浮点数解,但无整数解; +返回-1表示无解; +返回0表示有唯一解; +返回大于0表示无穷解,返回值为自由变元的个数 +*/ +int Gauss(int equ,int var) //equ为方程个数,var为变元个数。增广矩阵为 equ 行 * (var+1) 列(下标均从0开始) +{ + int k, col; + int free_x_num; + int free_index; + memset(free_x,true,sizeof(free_x)); + /*化为阶梯矩阵*/ + for(k = 0, col = 0; k < equ && col < var; k++,col++) //枚举当前处理的行 + { + int max_r = k; //当前这列绝对值最大的行 + //找到该col列元素绝对值最大的那行 + for(int i = k + 1; i < equ; i++) + { + if(abs(a[i][col]) > abs(a[max_r][col])) + max_r = i; + } + if(a[max_r][col] == 0) //第col列第k行以下全是0,处理当前行的下一列即可 + { + k--; + continue; + } + if(max_r != k) + { + for(int j = col; j < var + 1; j++) //与第k行交换,减小除法时的误差 + swap(a[k][j],a[max_r][j]); + } + for(int i = k + 1; i < equ; i++) //消元,化为行阶梯矩阵 + { + if(a[i][col]) //非零元素 + { + int LCM = lcm(abs(a[i][col]),abs(a[k][col])); + int ta = LCM / abs(a[i][col]); + int tb = LCM / abs(a[k][col]); + if(a[i][col] * a[k][col] < 0) //两行对应元素异号 + tb = -tb; //其中一个元素系数取反 + for(int j = col; j < var + 1; j++) + a[i][j] = a[i][j] * ta - a[k][j] * tb; + } + } + } + + /*1.无解(行阶梯矩阵中存在(0,0,...;a)这样的行,其中 a != 0 */ + for(int i = k; i < equ; i++) + { + if(a[i][col]) + return -1; + } + /*2.无穷多解(行阶梯矩阵中出现(0,0,...,0;0)这样的行,则存在自由变元;出现的行数即为自由变元的个数*/ + if(k < var) + { + //自由变元有 (var - k) 个,即不确定的变元至少有 (var - k) 个 + for(int i = k - 1; i >= 0; i--) + { + //第0行到第k-1行不会是(0,0,...0;0) + free_x_num = 0; //用于判断该行中的不确定的变元的个数 + for(int j = 0; j < var; j++) + { + if(a[i][j] && free_x[j]) + { + free_x_num++; + free_index = j; + } + } + if(free_x_num > 1) //变元的个数超过1个,无法求解(它们仍然为不确定的变元) + continue; + //说明就只有一个不确定的变元free_index,那么可以求解出该变元,且该变元是确定的 + int tmp = a[i][var]; + for(int j = 0; j < var; j++) + { + if(a[i][j] != 0 && j != free_index) + tmp -= a[i][j] * x[j]; + } + x[free_index] = tmp / a[i][free_index]; //求出该变元 + free_x[free_index] = 0; //该变元是确定的 + } + return var - k; //返回自由变元数量 + } + /*3.唯一解*/ + for(int i = var - 1; i >= 0; i--) + { + int tmp = a[i][var]; + for(int j = i + 1; j < var; j++) + { + if(a[i][j]) + tmp -= a[i][j] * x[j]; + } + if(tmp % a[i][i]) + return -2; //有浮点数解,但无整数解 + x[i] = tmp / a[i][i]; + } + return 0; +} diff --git "a/\346\225\260\345\255\246/\351\253\230\346\226\257\346\266\210\345\205\203\346\263\225\357\274\210\346\265\256\347\202\271\346\225\260\357\274\211.cpp" "b/\346\225\260\345\255\246/\351\253\230\346\226\257\346\266\210\345\205\203\346\263\225\357\274\210\346\265\256\347\202\271\346\225\260\357\274\211.cpp" new file mode 100644 index 0000000..367a876 --- /dev/null +++ "b/\346\225\260\345\255\246/\351\253\230\346\226\257\346\266\210\345\205\203\346\263\225\357\274\210\346\265\256\347\202\271\346\225\260\357\274\211.cpp" @@ -0,0 +1,96 @@ + +//EPS设置到1e-9 +#define MAXN 205 + +/*模板1*/ +double a[MAXN][MAXN]; //系数矩阵 +double x[MAXN]; //解集(初始化时存储增广矩阵的常系数) + +/* +高斯消元解浮点数系数方程 +返回0表示无解,返回1表示有解 +*/ +int Gauss(int equ, int var) //equ为方程数,var为未知数个数 +{ + int k, col; + for(k = 0, col = 0; k < equ && col < var; k++,col++) + { + int max_r = k; + for(int i = k + 1; i < equ; i++) + { + if(fabs(a[i][col]) > fabs(a[max_r][col])) + max_r = i; + } + if(fabs(a[max_r][col]) < EPS) + return 0; + if(k != max_r) + { + for(int j = col; j < var; j++) + swap(a[k][j],a[max_r][j]); + swap(x[k],x[max_r]); + } + x[k] /= a[k][col]; + for(int j = col + 1; j < var; j++) + a[k][j] /= a[k][col]; + a[k][col] = 1; + for(int i = 0; i < equ; i++) + { + if(i != k) + { + x[i] -= x[k] * a[i][col]; + for(int j = col + 1; j < var; j++) + a[i][j] -= a[k][j] * a[i][col]; + a[i][col] = 0; + } + } + } + return 1; +} + + + +/*模板2*/ +double a[maxn][maxn]; //增广矩阵 +double x[maxn]; //解集 + +/* +高斯消元解浮点数系数方程 +返回0表示无解,返回1表示有解 +*/ +int Gauss(int equ, int var) //equ为方程数,var为未知数个数 +{ + int k, col; + for(k = 0, col = 0; k < equ && col < var; k++, col++) + { + int max_r = k; + for(int i = k + 1; i < equ; i++) //找到最大的数所在的行 + { + if(fabs(a[i][col]) > fabs(a[max_r][col])) + max_r = i; + } + if(fabs(a[max_r][col]) < EPS) + return 0; + if(k != max_r) //交换行 + { + for(int j = col; j < var + 1; j++) + swap(a[k][j], a[max_r][j]); + } + for(int i = k+1; i < equ; i++) //消去 + { + if(a[i][col]) + { + double tmp = -a[i][col] / a[k][col]; + for(int j = col; j < var + 1; j++) + a[i][j] += tmp * a[k][j]; + } + } + } + for(int i = equ - 1; i >= 0; i--) //回代 + { + double tmp = a[i][var]; + for(int j = i + 1; j < var; j++) + tmp -= x[j] * a[i][j]; + x[i] = tmp / a[i][i]; + } + return 1; +} diff --git "a/\346\225\260\346\215\256\347\273\223\346\236\204/ST\350\241\250RMQ.cpp" "b/\346\225\260\346\215\256\347\273\223\346\236\204/ST\350\241\250RMQ.cpp" new file mode 100644 index 0000000..af278e5 --- /dev/null +++ "b/\346\225\260\346\215\256\347\273\223\346\236\204/ST\350\241\250RMQ.cpp" @@ -0,0 +1,27 @@ + +int logg[MAXN]; //计算log2(i) +int st[21][MAXN]; + +void init_rmq(int n) +{ + logg[1] = 0; + for(int i = 2; i <= n; i++) //预处理log2(i) + logg[i] = logg[i >> 1] + 1; + for(int i = 1; i <= n; i++) //初始化ST表 + { + scanf("%d", &st[0][i]); + //st[0][i] = a[i]; + } + for(int j = 1; (1 << j) < n; j++) //预处理计算出ST表 + { + //for(int i = 0; i < n - (1 << j) + 1; i++) + for(int i = 1; i + (1 << j) - 1 <= n; i++) + st[j][i] = max/min(st[j - 1][i], st[j - 1][i + (1 << (j - 1))]); + } +} + +int RMQ(int l, int r) //利用ST表O(1)复杂度RMQ +{ + int k = logg[r - l + 1]; + return max/min(st[k][l], st[k][r - (1 << k) + 1]); +} diff --git "a/\346\225\260\346\215\256\347\273\223\346\236\204/\344\272\214\347\273\264\346\240\221\347\212\266\346\225\260\347\273\204.cpp" "b/\346\225\260\346\215\256\347\273\223\346\236\204/\344\272\214\347\273\264\346\240\221\347\212\266\346\225\260\347\273\204.cpp" new file mode 100644 index 0000000..d89141b --- /dev/null +++ "b/\346\225\260\346\215\256\347\273\223\346\236\204/\344\272\214\347\273\264\346\240\221\347\212\266\346\225\260\347\273\204.cpp" @@ -0,0 +1,24 @@ +//二维树状数组模板 + +int bit2D[MAXN][MAXN]; +int n,m; + +void add2D(int x, int y, int val) //类似于前缀和 +{ + for(int i = x; i <= n; i += lowbit(i)) //n为矩阵其中一维的大小 + { + for(int j = y; j <= m; j += lowbit(j)) //m为矩阵另外一维的大小 + bit2D[i][j] += val; + } +} + +int getSum2D(int x,int y) +{ + int sum = 0; + for(int i = x; i > 0; i -= lowbit(i)) + { + for(int j = y; j > 0; j -= lowbit(j)) + sum += bit2D[i][j]; + } + return sum; +} diff --git "a/\346\225\260\346\215\256\347\273\223\346\236\204/\345\217\257\344\277\256\346\224\271\357\274\210\346\222\244\351\224\200\357\274\211\345\271\266\346\237\245\351\233\206.cpp" "b/\346\225\260\346\215\256\347\273\223\346\236\204/\345\217\257\344\277\256\346\224\271\357\274\210\346\222\244\351\224\200\357\274\211\345\271\266\346\237\245\351\233\206.cpp" new file mode 100644 index 0000000..d347cf2 --- /dev/null +++ "b/\346\225\260\346\215\256\347\273\223\346\236\204/\345\217\257\344\277\256\346\224\271\357\274\210\346\222\244\351\224\200\357\274\211\345\271\266\346\237\245\351\233\206.cpp" @@ -0,0 +1,113 @@ + +const int MAXN = 100005; + + +/* 单点修改并查集 */ + +int fa[MAXN << 1], rk[MAXN << 1]; //结点数量(集合的秩) + +void init(int n) +{ + for(int i = 1; i <= n; i++) + { + fa[i] = fa[i + n] = i + n; + rk[i + n] = 1; + } +} + +int findSet(int x) +{ + if(x != fa[x]) + return fa[x] = findSet(fa[x]); + return fa[x]; +} + +void unionSet(int x, int y) +{ + int fx = findSet(x); + int fy = findSet(y); + if(fx != fy) + { + //if(rk[fx] > rk[fy]) //可以不按秩合并 + // swap(fx, fy); + fa[fx] = fy; + rk[fy] += rk[fx]; + } +} + +void modifyNode(int x, int y) //修改结点的归属集合(将结点x从原集合取出,加入到结点y所在的集合) +{ + int fx = findSet(x); + int fy = findSet(y); + if(fx != fy) + { + fa[x] = fy; + rk[fx]--; + rk[fy]++; + } +} + + +/* 可撤销的并查集 */ + +//按秩合并,不可路径压缩 +class Undo_DSU +{ +public: + int fa[MAXN << 1], rk[MAXN << 1]; //结点数量(集合的秩) + PII sta[MAXN << 1]; //手动模拟栈 + int top; + //stack sta; + + void init(int n) + { + top = -1; + //while(!sta.empty()) + // sta.pop(); + for(int i = 1; i <= n; i++) + { + fa[i] = i; + rk[i] = 1; + } + } + + int findSet(int x) + { + if(x != fa[x]) + return findSet(fa[x]); //不可路径压缩 + return x; //return fa[x]; + } + + bool unionSet(int x, int y) + { + int fx = findSet(x); + int fy = findSet(y); + if(fx == fy) + return false; + if(rk[fx] > rk[fy]) + { + swap(fx, fy); + swap(x, y); + } + fa[fx] = fy; //按秩合并 + rk[fy] += rk[fx]; + sta[++top] = MP(fx, fy); + //sta.push(MP(fx, fy)); + return true; + } + + void undo() + { + /*if(!sta.empty()) + { + PII cur = sta.top(); + sta.pop(); + */ + if(~top) //有可以撤销的合并记录 + { + PII cur = sta[top--]; + fa[cur.first] = cur.first; + rk[cur.second] -= rk[cur.first]; + } + } +} dsu; diff --git "a/\346\225\260\346\215\256\347\273\223\346\236\204/\346\240\221\347\212\266\346\225\260\347\273\204.cpp" "b/\346\225\260\346\215\256\347\273\223\346\236\204/\346\240\221\347\212\266\346\225\260\347\273\204.cpp" new file mode 100644 index 0000000..63c36b3 --- /dev/null +++ "b/\346\225\260\346\215\256\347\273\223\346\236\204/\346\240\221\347\212\266\346\225\260\347\273\204.cpp" @@ -0,0 +1,23 @@ +//树状数组模板 + +int bit[MAXN]; //注意,当数值范围太大的时候应该先离散化 + +void add(int i, int x) +{ + while(i <= MaxVal) //MaxVal等于数值的最大值而不是数组的大小 + { + bit[i] += x; + i += lowbit(i); + } +} + +int getsum(int i) +{ + int sum = 0; + while(i > 0) + { + sum += bit[i]; + i -= lowbit(i); + } + return sum; +} diff --git "a/\346\225\260\346\215\256\347\273\223\346\236\204/\346\240\221\351\223\276\345\211\226\345\210\206.cpp" "b/\346\225\260\346\215\256\347\273\223\346\236\204/\346\240\221\351\223\276\345\211\226\345\210\206.cpp" index 6ddece2..7ed5c05 100644 --- "a/\346\225\260\346\215\256\347\273\223\346\236\204/\346\240\221\351\223\276\345\211\226\345\210\206.cpp" +++ "b/\346\225\260\346\215\256\347\273\223\346\236\204/\346\240\221\351\223\276\345\211\226\345\210\206.cpp" @@ -1,140 +1,194 @@ -class TreeChain{ + +/** + fa[]表示结点的父亲 + pos[]表示树剖分以后结点的dfs序 + dep[]表示结点的深度 + top[]表示结点所在的重链的顶端结点 + son[]表示结点的重儿子(size[]值最大的子结点) + sz[]表示以该结点为根的子树的结点数 + rk[]表示当前dfs序在树中所对应的结点 + */ + +class TreeChain +{ public: - struct Edge{ + struct Edge + { int u,v; - Edge(){} - Edge(int u,int v):u(u),v(v){} - } e[MAXN<<1]; - int cnt,ql,qr,val; - int node[MAXN]; - int fa[MAXN],pos[MAXN],dep[MAXN],top[MAXN],son[MAXN],sz[MAXN]; - int head[MAXN],nxt[MAXN<<1]; - int mx[MAXN<<2],p[MAXN<<2]; + Edge() {} + Edge(int u, int v) : u(u), v(v) {} + } e[MAXN << 1]; + int cnt, ql, qr, val; + int fa[MAXN], pos[MAXN], dep[MAXN], top[MAXN], son[MAXN], sz[MAXN], rk[MAXN]; + int head[MAXN], nxt[MAXN<<1]; + int mx[MAXN<<2], p[MAXN<<2]; int seg_nd; - - void init(int n){ + + void init(int n) + { cnt = seg_nd = 0; fa[1] = -1; - for(int i = 0;i<=n;i++) head[i] = -1; + for(int i = 0; i <= n; i++) + head[i] = -1; } - - void addEdge(int u,int v){ - e[cnt] = Edge(u,v); + + void addEdge(int u, int v) + { + e[cnt] = Edge(u, v); int tmp = head[u]; head[u] = cnt; nxt[cnt++] = tmp; } - - void dfs1(int u,int d){ - dep[u] = d;sz[u] = 1;son[u] = -1; + + void dfs1(int u, int d) //第一次dfs,处理dep,sz,son,fa数组 + { + dep[u] = d; + sz[u] = 1; + son[u] = -1; int mx = 0; - for(int i = head[u];~i;i = nxt[i]){ - Edge& ed = e[i]; - if(ed.v==fa[u]) continue; + for(int i = head[u]; ~i; i = nxt[i]) + { + Edge &ed = e[i]; + if(ed.v == fa[u]) + continue; fa[ed.v] = u; - dfs1(ed.v,d+1); - sz[u]+=sz[ed.v]; - if(mxdep[v]) swap(u,v); - // ql = pos[son[u]],qr = pos[v];//边分治 - ql = pos[u],qr = pos[v];//点分治 - _add(ql,qr,z); + //if(u == v) return; //边分治 + if(u == v); //点分治 + if(dep[u] > dep[v]) + swap(u,v); + //ql = pos[son[u]], qr = pos[v]; //边分治 + ql = pos[u], qr = pos[v]; //点分治 + _add(ql, qr, z); } - - int find(int u,int v){ + + int find(int u, int v) + { int ans = 0; - int fu = top[u],fv = top[v]; - while(fu!=fv){ - if(dep[fu]dep[v]) swap(u,v); - ql = pos[son[u]],qr = pos[v];// + if(u == v) + return ans; + if(dep[u] > dep[v]) + swap(u, v); + ql = pos[son[u]], qr = pos[v]; // return ans; } - - void push_Up(int l,int r,int rt){ - if(mx[rt<<1]>=mx[rt<<1|1]){ - mx[rt] = mx[rt<<1]; - p[rt] = p[rt<<1]; - }else{ - mx[rt] = mx[rt<<1|1]; - p[rt] = p[rt<<1|1]; + + void pushUp(int l, int r, int rt) + { + if(mx[rt << 1] >= mx[rt << 1 | 1]) + { + mx[rt] = mx[rt << 1]; + p[rt] = p[rt << 1]; + } + else + { + mx[rt] = mx[rt << 1 | 1]; + p[rt] = p[rt << 1 | 1]; } } - - void build(int l,int r,int rt){ - if(l==r){ + + void build(int l, int r, int rt) + { + if(l == r) + { p[rt] = l; mx[rt] = 0; - }else{ - int mid = (l+r)>>1; + } + else + { + int mid = (l + r) >> 1; build(lson); build(rson); - push_Up(l,r,rt); + pushUp(l, r, rt); } } - - void update(int l,int r,int rt){ - if(l==r) mx[rt]+=val; - else{ - int mid = (l+r)>>1; - if(ql<=mid) update(lson); - else update(rson); - push_Up(l,r,rt); + + void update(int l, int r, int rt) + { + if(l == r) + mx[rt] += val; + else + { + int mid = (l + r) >> 1; + if(ql <= mid) + update(lson); + else + update(rson); + pushUp(l, r, rt); } } - - int query(int l,int r,int rt){ - if(mx[rt]==0) return 0; + + int query(int l, int r, int rt) + { + if(mx[rt] == 0) + return 0; return p[1]; } } tc; /* - int main(void){ - tc.dfs1(1,0); - tc.dfs2(1,1); - } - */ +int main() +{ + tc.dfs1(1,0); + tc.dfs2(1,1); +} +*/ diff --git "a/\346\225\260\346\215\256\347\273\223\346\236\204/\347\202\271\345\210\206\346\262\273.cpp" "b/\346\225\260\346\215\256\347\273\223\346\236\204/\347\202\271\345\210\206\346\262\273.cpp" index 57fb524..0b761e5 100644 --- "a/\346\225\260\346\215\256\347\273\223\346\236\204/\347\202\271\345\210\206\346\262\273.cpp" +++ "b/\346\225\260\346\215\256\347\273\223\346\236\204/\347\202\271\345\210\206\346\262\273.cpp" @@ -1,86 +1,228 @@ -class NodeDiv{ +/* 我的模板 */ + +class NodeDiv +{ +public: +#define MAXN 10005 + + int head[MAXN]; + struct Edge + { + int to, cost, nxt; + Edge() {} + Edge(int to, int cost, int nxt) : to(to), cost(cost), nxt(nxt) {} + } e[MAXN << 1]; + + int sz[MAXN]; //以每个结点为根子树的结点数(包含自身) + int dp[MAXN]; //dp[i]表示沿树路径到第i个点时子树结点数的最大值(不含自身) + int dis[MAXN]; //存储各个点到重心的距离(单纯存储距离值,不对应结点) + bool vis[MAXN]; + int cnt, tot; + int nodecnt; //当前子树中所有结点数 + int rt; //求得当前子树的重心 + int ans; + int n, k; + + void init(int n, int m) + { + this -> n = n; + this -> m = m; + cnt = rt = 0; + memset(head, -1, sizeof(head)); + memset(vis, false, sizeof(vis)); + } + + inline void addEdge(int u, int v, int w) + { + e[cnt].to = v; + e[cnt].cost = w; + e[cnt].nxt = head[u]; + head[u] = cnt++; + } + + void dfs(int u, int fa) //树形dp求树的重心 + { + dp[u] = 0, sz[u] = 1; + for(int i = head[u]; ~i; i = e[i].nxt) + { + int v = e[i].to; + if(v != fa && !vis[v]) + { + dfs(v, u); + sz[u] += sz[v]; + dp[u] = max(dp[u], sz[v]); + } + } + dp[u] = max(dp[u], nodecnt - sz[u]); //树的重心的定义:以该点为根的有根树,最大子树的结点数最小 + if(dp[u] < dp[rt]) + rt = u; + } + + void getDis(int u, int fa, int d) + { + dis[++tot] = d; + for(int i = head[u]; ~i; i = e[i].nxt) + { + int v = e[i].to, w = e[i].cost; + if(v != fa && !vis[v] && d + w <= k) + getDis(v, u, d + w); + } + } + + int cal(int u, int d) + { + tot = 0; + int sum = 0; + getDis(u, 0, d); + sort(dis + 1, dis + 1 + tot); + int l = 1, r = tot; + while(l < r) + { + /* 计算符合条件的路径数 */ + } + return sum; + } + + void solve(int u) + { + vis[u] = true; + ans += cal(u, 0); + for(int i = head[u]; ~i; i = e[i].nxt) + { + int v = e[i].to; + if(!vis[v]) + { + ans -= cal(v, e[i].cost); + rt = 0; + nodecnt = sz[v]; + dfs(v, 0); //dfs(v, u) 也可 + solve(rt); + } + } + } + + void main() //调用方法 + { + memset(vis, false, sizeof(vis)); + dp[0] = INF; + nodecnt = n; + ans = rt = 0; + dfs(1, 0); + solve(rt); + } +} nodediv; + + +/* 发神的模板 */ + +class NodeDiv +{ public: #define MAXN 10005 #define MAXE 20005 - int n,k; - int head[MAXN],nxt[MAXE],dis[MAXN],ret[MAXN]; - struct Edge{ - int v,w; - Edge(){} - Edge(int v,int w):v(v),w(w){} - } e[MAXE]; - int cnt; - int sz[MAXN],mx[MAXN],fa[MAXN]; - bool vis[MAXN]; - - void init(int n){ - cnt = 0; - for(int i = 0;i> 1)); //每个点的需要更新的值乘以的个数 + Sum[rt << 1 | 1] += Lazy[rt] * (val >> 1); //同上 + Lazy[rt << 1] += Lazy[rt]; //这个区间需要更新的个数 + Lazy[rt << 1 | 1] += Lazy[rt]; + Lazy[rt] = 0; + } + } + + void pushUp(int rt) + { + Max[rt] = max(Max[rt << 1], Max[rt << 1 | 1]); + Min[rt] = min(Min[rt << 1], Min[rt << 1 | 1]); + Sum[rt] = Sum[rt << 1] + Sum[rt <<1 | 1]; + } + + void build(int l, int r, int rt) //建树 + { + Lazy[rt] = 0; + if(l == r) + { + //scanf("%d", &Sum[rt]); + Sum[rt] = a[l]; + Min[rt] = INF; + Max[rt] = -1; + return ; + } + int mid = (l + r) >> 1; + build(lson); + build(rson); + pushUp(rt); + } + + //调用方式:function(cur, val, left, right, nodeid); + //cur--原来的点,val--更新、询问等操作的有关值,left--更新的左边界,right--更新的右边界,nodeid--结点编号 + void updateNode(int x, Type val, int l, int r, int rt) //单点更新(替换) + { + if(l == r) + { + Max[rt] = val; + Min[rt] = val; + Sum[rt] = val; + return ; + } + int mid = (l + r) >> 1; + if(x <= mid) + updateNode(x, val, lson); + else + updateNode(x, val, rson); + pushUp(rt); + } + + void modifyNode(int x, Type val, int l, int r, int rt) //单点增减 + { + if(l == r) + { + Sum[rt] += val; + return ; + } + int mid = (l + r) >> 1; + if(x <= mid) + addNode(x, val, lson); + else + addNode(x, val, rson); + pushUp(rt); + } + + Type queryNode(int x, int l, int r, int rt) //单点查询 + { + if(l == r) + return Sum[rt]; + //pushDown(rt,r-l+1); + int mid = (l + r) >> 1; + if(x <= mid) + return queryNode(x, lson); + else + return queryNode(x, rson); + } + + void updateInterval(int L, int R, Type val, int l, int r, int rt) //区间更新 + { + if(L <= l && r <= R) + { + Lazy[rt] += val; + Sum[rt] += val * (r - l + 1); + return ; + } + pushDown(rt, r - l + 1); //向下更新枝叶的值 + int mid = (l + r) >> 1; + if(L <= mid) + updateInterval(L, R, val, lson); + if(R > mid) + updateInterval(L, R, val, rson); + pushUp(rt); + } + + Type queryMax/Min(int L, int R, int l, int r, int rt) //区间求最值 + { + if(L <= l && r <= R) + return Max/Min[rt]; + int mid = (l + r) >> 1; + Type ret = -1/INF/LINF; + if(L <= mid) + ret = max/min(ret, queryMax/Min(L, R, lson)); + if(R > mid) + ret = max/min(ret, queryMax/Min(L, R, rson)); + return ret; + } + + Type querySum(int L, int R, int l, int r, int rt) //区间求和 + { + if(L <= l && r <= R) + return Sum[rt]; + pushDown(rt, r - l + 1); //向下更新枝叶的值 + int mid = (l + r) >> 1; + Type ret = 0; + if(L <= mid) + ret += querySum(L, R, lson); + if(R > mid) + ret += querySum(L, R, rson); + return ret; + } +} segtree; + + +//线段树 + 离散化 +typedef int Type; + +Type sum[MAXN]; +Type lazy[MAXN<<3]; +int Hash[MAXN<<1]; + +struct DiscreteNode +{ + int x,y; +} data[MAXN]; + +void pushDown(int l, int r, int rt) //离散化后区间标记下传 +{ + int mid = (l + r) >> 1; + if(~lazy[rt]) + { + sum[rt << 1] = lazy[rt] * (Hash[mid + 1] - Hash[l]); + sum[rt << 1 | 1] = lazy[rt] * (Hash[r + 1] - Hash[mid + 1]); + lazy[rt << 1] = lazy[rt << 1 | 1] = lazy[rt]; + lazy[rt] = -1; + } +} + +int main() +{ + int n, q; + scanf("%d%d", &n, &q); + memset(lazy, -1, sizeof(lazy)); + /* sort + unique 离散化*/ + int cnt = 0; + for(int i = 1; i <= q; i++) + { + scanf("%d%d", &data[i].x, &data[i].y); + Hash[++cnt] = data[i].x; + Hash[++cnt] = ++data[i].y; //直接将右端点+1 + } + Hash[++cnt] = 1; + Hash[++cnt] = 10000001; + sort(Hash + 1, Hash + 1 + cnt); + cnt = unique(Hash + 1, Hash + 1 + cnt) - Hash - 1; + cnt--; + for(int i = 1; i <= q; i++) + { + int x = lower_bound(Hash + 1, Hash + 1 + cnt, data[i].x) - Hash; + int y = lower_bound(Hash + 1, Hash + 1 + cnt, data[i].y) - Hash - 1; + } + /* + 这里为建树操作等,根据题目要求灵活应对。 + */ + return 0; +} diff --git "a/\346\225\260\346\215\256\347\273\223\346\236\204/\347\272\277\346\256\265\346\240\221\357\274\210\347\273\223\346\236\204\344\275\223\347\211\210\357\274\211.cpp" "b/\346\225\260\346\215\256\347\273\223\346\236\204/\347\272\277\346\256\265\346\240\221\357\274\210\347\273\223\346\236\204\344\275\223\347\211\210\357\274\211.cpp" new file mode 100644 index 0000000..0151e3d --- /dev/null +++ "b/\346\225\260\346\215\256\347\273\223\346\236\204/\347\272\277\346\256\265\346\240\221\357\274\210\347\273\223\346\236\204\344\275\223\347\211\210\357\274\211.cpp" @@ -0,0 +1,243 @@ +//线段树(结构体版) + +typedef LL Type; + +struct Node +{ + int l,r; + Type sum,lazy; +} tree[MAXN<<2]; + +void pushUp(int rt) +{ + tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum; +} + +void build(int l,int r,int rt) //建树 +{ + tree[rt].l = l, tree[rt].r = r; + if(tree[rt].l == tree[rt].r) + { + scanf("%d",&tree[rt].sum); + return; + } + int mid = (l + r) >> 1; + build(lson); + build(rson); + pushUp(rt); +} + +void pushDown(int rt)// 标记下传 +{ + if(tree[rt].lazy) + { + tree[rt<<1].lazy += tree[rt].lazy; + tree[rt<<1|1].lazy += tree[rt].lazy; + tree[rt<<1].sum += tree[rt].lazy * (tree[rt<<1].r - tree[rt<<1].l + 1); + tree[rt<<1|1].sum += tree[rt].lazy * (tree[rt<<1|1].r - tree[rt<<1|1].l + 1); + tree[rt].lazy = 0; + } +} + +Type queryPoint(Type val,int rt) //单点查询 +{ + if(tree[rt].l == tree[rt].r) + return tree[rt].sum; + pushDown(rt); + int mid = tree[rt].l + (tree[rt].r - tree[rt].l) >> 1; + if(x <= mid) + return queryPoint(val,rt<<1); + else + return queryPoint(val,rt<<1|1); +} + +void updatePoint(int x,Type val,int rt) //单点修改 +{ + if(tree[rt].l == tree[rt].r) + { + tree[rt].sum += val; + return; + } + int mid = tree[rt].l + (tree[rt].r - tree[rt].l) >> 1; + if(x <= mid) + updatePoint(x,val,rt<<1); + else + updatePoint(x,val,rt<<1|1); + pushUp(rt); +} + +Type queryInterval(int ll,int rr,int rt) //区间查询 +{ + if(ll <= tree[rt].l && tree[rt].r <= rr) + return tree[rt].sum; + pushDown(rt); + int mid = tree[rt].l + (tree[rt].r - tree[rt].l) >> 1; + Type ans = 0; + if(ll <= mid) + ans += queryInterval(ll,rr,rt<<1); + if(rr > mid) + ans += queryInterval(ll,rr,rt<<1|1); + return ans; +} + +void updateInterval(Type val,int ll,int rr,int rt) //区间修改 +{ + if(ll <= tree[rt].l && tree[rt].r <= rr) + { + tree[rt].sum += val * (tree[rt].r - tree[rt].l + 1); + tree[rt].lazy += val; + return ; + } + pushDown(rt); + int mid = tree[rt].l + (tree[rt].r - tree[rt].l) >> 1; + if(ll <= mid) + updateInterval(val,ll,rr,rt<<1); + if(rr > mid) + updateInterval(val,ll,rr,rt<<1|1); + pushUp(rt); +} + +int main() +{ + scanf("%d",&n); //n个节点 + build(1,1,n); //建树 + scanf("%d",&m); //m种操作 + for(int i=1; i<=m; i++) + { + scanf("%d",&p); + ans=0; + if(p==1) + { + scanf("%d",&x); + queryPoint(1);//单点查询,输出第x个数 + printf("%d",ans); + } + else if(p==2) + { + scanf("%d%d",&x,&y); + updatePoint(1);//单点修改 + } + else if(p==3) + { + scanf("%d%d",&a,&b);//区间查询 + queryInterval(1); + printf("%d\n",ans); + } + else + { + scanf("%d%d%d",&a,&b,&y);//区间修改 + updateInterval(1); + } + } +} + + +//线段树+离散化 +typedef int Type; + +struct Node +{ + int l,r; + Type sum,lazy; +} tree[MAXN<<3]; + +struct DiscreteNode +{ + int x,y; +} data[MAXN<<1]; //离散化用 + +int Hash[MAXN<<1]; //对应离散化前点的序号 + +void pushDown(int rt) //离散化后区间标记下传 +{ + int l = tree[rt].l, r = tree[rt].r; + int mid = (l + r) >> 1; + if(~tree[rt].lazy) + { + tree[rt<<1].sum = tree[rt].lazy * (Hash[mid+1] - Hash[l]); + tree[rt<<1|1].sum = tree[rt].lazy * (Hash[r+1] - Hash[mid+1]); + tree[rt<<1].lazy = tree[rt<<1|1].lazy = tree[rt].lazy; + tree[rt].lazy = -1; + } +} + +int main() +{ + int n,q; + scanf("%d%d",&n,&q); + /*sort+unique离散化*/ + int cnt=0; + for(int i=1; i<=q; i++) + { + scanf("%d%d",&data[i].x,&data[i].y); + Hash[++cnt]=data[i].x; + Hash[++cnt]=++data[i].y; //直接将右端点+1 + } + Hash[++cnt]=1; + Hash[++cnt]=n+1; + sort(Hash+1,Hash+1+cnt); + cnt=unique(Hash+1,Hash+1+cnt)-Hash-1; + cnt--; + for(int i=1; i<=q; i++) + { + data[i].x=lower_bound(Hash+1,Hash+1+cnt,data[i].x)-Hash; + data[i].y=lower_bound(Hash+1,Hash+1+cnt,data[i].y)-Hash-1; + } + /* + 这里为建树操作等,根据题目要求灵活应对。 + */ + return 0; +} + + +//线段树区间合并(求区间连续1) +typedef int Type; + +struct Node +{ + int l,r; + int cover; + int ls,rs,ms; //ls表示从左端开始的最大连续区间,rs表示从右端开始的最大连续区间,ms表示该区间内的最大连续区间 +} tree[MAXN<<2]; + +void pushUp(int rt) +{ + tree[rt].ls = tree[rt<<1].ls; + tree[rt].rs = tree[rt<<1|1].rs; + tree[rt].ms = max(max(tree[rt<<1].ms,tree[rt<<1|1].ms),tree[rt<<1].rs+tree[rt<<1|1].ls); + if(tree[rt<<1].ls == tree[rt<<1].r - tree[rt<<1].l + 1) + tree[rt].ls += tree[rt<<1|1].ls; + if(tree[rt<<1|1].rs == tree[rt<<1|1].r - tree[rt<<1|1].l + 1) + tree[rt].rs += tree[rt<<1].rs; +} + +void pushDown(int rt) +{ + if(~tree[rt].cover) + { + tree[rt<<1].cover = tree[rt<<1|1].cover = tree[rt].cover; + if(tree[rt].cover) + { + tree[rt<<1].ls = tree[rt<<1].rs = tree[rt<<1].ms = 0; + tree[rt<<1|1].ls = tree[rt<<1|1].rs = tree[rt<<1|1].ms = 0; + } + else + { + tree[rt<<1].ls = tree[rt<<1].rs = tree[rt<<1].ms = tree[rt<<1].r - tree[rt<<1].l + 1; + tree[rt<<1|1].ls = tree[rt<<1|1].rs = tree[rt<<1|1].ms = tree[rt<<1|1].r - tree[rt<<1|1].l + 1; + } + tree[rt].cover = -1; + } +} + +void build(int l,int r,int rt) +{ + tree[rt].l = l, tree[rt].r = r; + tree[rt].cover = -1; + tree[rt].ls = tree[rt].rs = tree[rt].ms = r - l + 1; + if(l == r) + return ; + int mid = (l + r) >> 1; + build(lson); + build(rson); +} diff --git "a/\346\225\260\346\215\256\347\273\223\346\236\204/\350\276\271\345\210\206\346\262\273.cpp" "b/\346\225\260\346\215\256\347\273\223\346\236\204/\350\276\271\345\210\206\346\262\273.cpp" new file mode 100644 index 0000000..4811437 --- /dev/null +++ "b/\346\225\260\346\215\256\347\273\223\346\236\204/\350\276\271\345\210\206\346\262\273.cpp" @@ -0,0 +1,228 @@ + +class EdgeDiv +{ +public: + #define MAXN 200005 + #define MAXE MAXN << 4 //边至少开到点的16倍 + + int _head[MAXN], head[MAXN]; + struct Edge + { + int to, cost, nxt, pre; + Edge() {} + Edge(int to, int cost, int nxt, int pre) : to(to), cost(cost), nxt(nxt), pre(pre) {} + } _e[MAXE], e[MAXE]; //原图,重构得到的新图 + + int tail[MAXN]; + int sz[MAXN]; //子树包含的结点数 + int maxval; //记录子树的最大答案 + int rt; //根结点 + int midedge; //中心边 + int n, node; //原图结点数,重构得到的新图的结点数 + int _cnt, cnt; + + void _init() //原图初始化 + { + _cnt = 0; + memset(_head, -1, sizeof(_head)); + } + + void init() //重构后新图的初始化 + { + cnt = 0; + memset(head, -1, sizeof(head)); + } + + inline void _addEdge(int u, int v, int w) //原图的加边 + { + _e[_cnt].to = v; + _e[_cnt].cost = w; + _e[_cnt].nxt = _head[u]; + _head[u] = _cnt++; + } + + inline void addEdge(int u, int v, int w) //重构后新图的加边 + { + e[cnt].to = v; + e[cnt].cost = w; + e[cnt].nxt = head[u]; + head[u] = cnt++; + } + + void delEdge(int u, int i) //删除结点u的i号边 + { + if(head[u] == i) + head[u] = e[i].nxt; + else //跳过该边 + e[e[i].pre].nxt = e[i].nxt; + if(tail[u] == i) //指向u结点的最后一条边,相当于尾指针 + tail[u] = e[i].pre; + else + e[e[i].nxt].pre = e[i].pre; //双向链表修改前驱 + } + + void build(int u, int fa) //重构新图,保证每个点的度都不超过2 + { + int father = 0; + for(int i = _head[u]; ~i; i = _e[i].nxt) + { + int v = _e[i].to, w = _e[i].cost; + if(v != fa) + { + if(!father) //还没有增加子结点,直接连接 + { + addEdge(u, v, w); + addEdge(v, u, w); + father = u; + } + else //已经有一个子结点,则新建一个虚拟结点,把结点v连新结点上 + { + //虚拟结点到父结点建立权值为0的边 + node++; + addEdge(node, father, 0); + addEdge(father, node, 0); + //虚拟结点到子结点建立权值为w的边 + father = node; + addEdge(v, father, w); + addEdge(father, v, w); + } + build(v, u); + } + } + } + + inline void getPre() //得到每条边的前驱,nxt是下一条边的编号,pre是上一条边的编号 + { + memset(tail, -1, sizeof(tail)); + for(int i = 1; i <= node; i++) + { + for(int j = head[i]; ~j; j = e[j].nxt) + { + e[j].pre = tail[i]; + tail[i] = j; //指向结点u的最后一条边,相当于尾指针 + } + } + } + + struct Point + { + int u, dis; + Point() {} + Point(int u, int dis) : u(u), dis(dis) {} + bool operator < (const Point &p) const + { + return dis < p.dis; //优先弹出距离最小的点(保留距离最大的) + //return dis > p.dis; //优先弹出距离最大的点(保留距离小的点) + } + }; + + struct Node + { + int rt, midlen, ans; //根结点,中心边权值,答案(最长树链) + int ls, rs; //左右子树编号 + priority_queue pq; + } tr[MAXN << 1]; + + void dfsSize(int u, int fa, int d) //求解每棵子树的大小,建立距离树 + { + _addEdge(u, rt, d); //添加每个点到root的距离到距离树(有向边 u -> root) + //if() //根据题目条件让点入队 + tr[rt].pq.push(Point(u, d)); + sz[u] = 1; + for(int i = head[u]; ~i; i = e[i].nxt) + { + int v = e[i].to, w = e[i].cost; + if(v != fa) + { + dfsSize(v, u, d + w); + sz[u] += sz[v]; + } + } + } + + void dfsMidEdge(int u, int eid) //找中心边 + { + if(max(sz[u], sz[tr[rt].rt] - sz[u]) < maxval) + { + maxval = max(sz[u], sz[tr[rt].rt] - sz[u]); //sz[tr[rt].rt]为该子树的结点总数 + midedge = eid; //中心边编号 + } + for(int i = head[u]; ~i; i = e[i].nxt) + { + int v = e[i].to; + if(i != (eid ^ 1)) //不是中心边的反向边 + dfsMidEdge(v, i); //递归寻找子树中的中心边 + } + } + + void pushUp(int rt) //更新编号为id边的答案(根据题目要求进行修改) + { + //tr[rt].ans = -1; + while(!tr[rt].pq.empty()) //优先队列弹出结点的条件 + tr[rt].pq.pop(); + /*int ls = tr[rt].ls, rs = tr[rt].rs; //ls为左儿子,rs为右儿子 + if(!ls && !rs) //该结点没有左右儿子 + { + //if() //根据题目条件修改答案 + tr[rt].ans = 0; + } + else + { + if(tr[ls].ans > tr[rt].ans) //左儿子的答案大于根的答案 + tr[rt].ans = tr[ls].ans; + if(tr[rs].ans > tr[rt].ans) //右儿子的答案大于根的答案 + tr[rt].ans = tr[rs].ans; + if(!tr[ls].pq.empty() && !tr[rs].pq.empty()) //左右子树的优先队列都不为空 + tr[rt].ans = max(tr[rt].ans, tr[ls].pq.top().dis + tr[rs].pq.top().dis + tr[rt].midlen); //左子树的最远距离+右子树的最远距离+中心边的长度 + }*/ + } + + void dfs(int u, int id) //边分治求解答案 + { + rt = id, maxval = node, midedge = -1; + tr[id].rt = u; + dfsSize(u, 0, 0); //dfs求解每棵子树的大小 + dfsMidEdge(u, -1); //找中心边 + if(~midedge) + { + int p1 = e[midedge].to, p2 = e[midedge ^ 1].to; //中心边的两个端点 + tr[id].midlen = e[midedge].cost; //中心边长度 + tr[id].ls = ++cnt, tr[id].rs = ++cnt; //左右子树 + //删除中心边 + delEdge(p1, midedge ^ 1); + delEdge(p2, midedge); + dfs(p1, tr[id].ls); + dfs(p2, tr[id].rs); + } + pushUp(id); + } + + void update(int u) //根据题意对结点进行修改 + { + for(int i = _head[u]; ~i; i = _e[i].nxt) + { + int v = _e[i].to, w = _e[i].cost; + //if() //根据题目条件修改 + tr[v].pq.push(Point(u, w)); + pushUp(v); + } + } + + void buildGraph() //建图 + { + // + } + + void solve(int n) + { + this -> n = n; + _init(); //原树的初始化 + buildGraph(); + init(); //初始化原树 + node = n; + build(1, 0); //重建树 + getPre(); //得到每条边的前驱 + _init(); //重建树后的原树不再需要,将其初始化用来存储距离树 + dfs(1, cnt = 1); //求解答案 + } +} edgediv; diff --git "a/\347\275\221\347\273\234\346\265\201/Dinic.cpp" "b/\347\275\221\347\273\234\346\265\201/Dinic.cpp" index fdb451b..f6b954d 100644 --- "a/\347\275\221\347\273\234\346\265\201/Dinic.cpp" +++ "b/\347\275\221\347\273\234\346\265\201/Dinic.cpp" @@ -1,79 +1,108 @@ -#define MAXN 100005 -#define MAXE 2000005 +const int MAXN = 100005; +const int MAXE = 2000005; -class Dinic{ +class Dinic +{ private: - int d[MAXN]; - int head[MAXN],nxt[MAXE],cur[MAXN]; - struct Edge{ - int from,to,cap,flow; - Edge(int from,int to,int cap,int flow):from(from),to(to),cap(cap),flow(flow){} - Edge(){} - } e[MAXE]; + int d[MAXN]; + int head[MAXN], nxt[MAXE], cur[MAXN]; + struct Edge + { + int from, to, cap, flow; + Edge(int from, int to, int cap, int flow) : from(from), to(to), cap(cap), flow(flow) {} + Edge() {} + } e[MAXE]; - int s,t,cnt; - int node; - bool bfs(){ - for(int i = 0;i q; - q.push(s); - while(!q.empty()){ - int x = q.front();q.pop(); - for(int i = head[x];~i;i = nxt[i]){ - Edge &ed = e[i]; - if(d[ed.to]==-1&&ed.cap>ed.flow){ - d[ed.to] = d[x]+1; - q.push(ed.to); - } - } - } - return d[t]!=-1; - } - int dfs(int x,int a){ - if(x==t||a==0) return a; - int flow = 0,f; - for(;~cur[x];cur[x] = nxt[cur[x]]){ - Edge &ed = e[cur[x]]; - if(d[ed.to]==d[x]+1&&(f = dfs(ed.to,min(ed.cap-ed.flow,a)))>0){ - flow+=f; - ed.flow+=f; - e[cur[x]^1].flow-=f; - a-=f; - if(a==0) break; - } - } - return flow; - } - - void addEdge(int from,int to,int cap){ - e[cnt] = Edge(from,to,cap,0); - int tmp = head[from]; - head[from] = cnt; - nxt[cnt++] = tmp; - e[cnt] = Edge(to,from,0,0); - tmp = head[to]; - head[to] = cnt; - nxt[cnt++] = tmp; - } + int s, t, cnt; + int n, m; + int node; + + bool bfs() + { + for(int i = 0; i <= node; i++) + d[i] = -1; + d[s] = 0; + queue q; + q.push(s); + while(!q.empty()) + { + int x = q.front(); + q.pop(); + for(int i = head[x]; ~i; i = nxt[i]) + { + Edge &ed = e[i]; + if(d[ed.to] == -1 && ed.cap > ed.flow) + { + d[ed.to] = d[x] + 1; + q.push(ed.to); + } + } + } + return d[t] != -1; + } + int dfs(int x,int a) + { + if(x == t || a == 0) + return a; + int flow = 0, f; + for(; ~cur[x]; cur[x] = nxt[cur[x]]) + { + Edge &ed = e[cur[x]]; + if(d[ed.to] == d[x] + 1 && (f = dfs(ed.to, min(ed.cap - ed.flow, a))) > 0) + { + flow += f; + ed.flow += f; + e[cur[x] ^ 1].flow -= f; + a -= f; + if(a == 0) + break; + } + } + return flow; + } + + void addEdge(int from, int to, int cap) + { + e[cnt] = Edge(from, to, cap, 0); + int tmp = head[from]; + head[from] = cnt; + nxt[cnt++] = tmp; + e[cnt] = Edge(to, from, 0, 0); + tmp = head[to]; + head[to] = cnt; + nxt[cnt++] = tmp; + } public: - void init(){ - cnt = node = 0; - } + void init(int n, int m) + { + cnt = 0; + this -> n = n; + this -> m = m; + } - int maxFlow(){ - int flow = 0; - while(bfs()){ - for(int i = 0;i n = n; + this -> m = m; + } + + void addEdge(int from,int to,int cap,CostType cost) + { + e[cnt] = Edge(from,to,cap,0,cost); + int tmp = head[from]; + head[from] = cnt; + nxt[cnt++] = tmp; + e[cnt] = Edge(to,from,0,0,-cost); + tmp = head[to]; + head[to] = cnt; + nxt[cnt++] = tmp; + } + + bool spfa(int &flow,CostType &cost) + { + for(int i = 0; i<=node; i++) + { + d[i] = INF; + inq[i] = false; + } + d[s] = 0,inq[s] = true,p[s] = 0,a[s] = INF; + queue q; + q.push(s); + while(!q.empty()) + { + int u = q.front(); + q.pop(); + inq[u] = false; + for(int i = head[u]; ~i; i = nxt[i]) + { + Edge &ed = e[i]; + if(ed.cap>ed.flow&&d[ed.to]>d[u]+ed.cost) + { + d[ed.to] = d[u]+ed.cost; + p[ed.to] = i; + a[ed.to] = min(a[u],ed.cap-ed.flow); + if(!inq[ed.to]) + { + inq[ed.to] = true; + q.push(ed.to); + } + } + } + } + if(d[t]==INF) return false; + flow+=a[t]; + cost+=d[t]*a[t]; + int u = t; + while(u!=s) + { + e[p[u]].flow+=a[t]; + e[p[u]^1].flow-=a[t]; + u = e[p[u]].from; + } + return true; + } - int head[MAXN],nxt[MAXE],a[MAXN],p[MAXN]; - bool inq[MAXN]; - CostType d[MAXN]; - int cnt,s,t; - int node; - - void init(){ - cnt = 0; - } + //CostType maxFlow() + int maxFlow() + { + int flow = 0; + CostType cost = 0; + while(spfa(flow,cost)); + return flow; + //return cost; + } - void addEdge(int from,int to,int cap,CostType cost){ - e[cnt] = Edge(from,to,cap,0,cost); - int tmp = head[from]; - head[from] = cnt; - nxt[cnt++] = tmp; - e[cnt] = Edge(to,from,0,0,-cost); - tmp = head[to]; - head[to] = cnt; - nxt[cnt++] = tmp; - } - bool spfa(int &flow,CostType &cost){ - for(int i = 0;i<=node;i++){ - d[i] = INF; - inq[i] = false; - } - d[s] = 0,inq[s] = true,p[s] = 0,a[s] = INF; - queue q; - q.push(s); - while(!q.empty()){ - int u = q.front();q.pop(); - inq[u] = false; - for(int i = head[u];~i;i = nxt[i]){ - Edge &ed = e[i]; - if(ed.cap>ed.flow&&d[ed.to]>d[u]+ed.cost){ - d[ed.to] = d[u]+ed.cost; - p[ed.to] = i; - a[ed.to] = min(a[u],ed.cap-ed.flow); - if(!inq[ed.to]){ - inq[ed.to] = true; - q.push(ed.to); - } - } - } - } - if(d[t]==INF) return false; - flow+=a[t]; - cost+=d[t]*a[t]; - int u = t; - while(u!=s){ - e[p[u]].flow+=a[t]; - e[p[u]^1].flow-=a[t]; - u = e[p[u]].from; - } - return true; - } - int maxFlow(){ - int flow = 0; - CostType cost = 0; - while(spfa(flow,cost)); - return flow; - } - void buildGraph(){ - memset(head,-1,sizeof(head)); - node = n; - s = 1,t = 1; - } - }; + void buildGraph() + { + memset(head,-1,sizeof(head)); + s = 0; + t = n; + node = t; + } +} mcmf; diff --git "a/\347\275\221\347\273\234\346\265\201/SAP.cpp" "b/\347\275\221\347\273\234\346\265\201/SAP.cpp" new file mode 100644 index 0000000..2e9fe45 --- /dev/null +++ "b/\347\275\221\347\273\234\346\265\201/SAP.cpp" @@ -0,0 +1,148 @@ + +#define MAXN 10010 +#define MAXE 1000010 + +class SAP_QuickVersion +{ +private: + struct Edge + { + int from,to,next,cap; + Edge(int from,int to,int next,int cap):from(from),to(to),next(next),cap(cap) {} + Edge() {} + } e[MAXE]; + + int cnt; + int head[MAXN]; + int dep[MAXN]; + int gap[MAXN];//gap[x]=y :说明残留网络中dep[i]==x的个数为y + + int n,m; + int node; //node是总的点的个数,包括源点和汇点 + + void addEdge(int u,int v,int w) + { + e[cnt].from=u; + e[cnt].to=v; + e[cnt].cap=w; + e[cnt].next=head[u]; + head[u]=cnt++; + e[cnt].from=v; + e[cnt].to=u; + e[cnt].cap=0; + e[cnt].next=head[v]; + head[v]=cnt++; + } + + void bfs(int st,int ed) + { + memset(dep,-1,sizeof(dep)); + memset(gap,0,sizeof(gap)); + gap[0] = 1; + int que[MAXN]; + int fnt,rear; + fnt = rear = 0; + dep[ed] = 0; + que[rear++] = ed; + while(fnt != rear) + { + int u = que[fnt++]; + if(fnt == MAXN) + fnt = 0; + for(int i=head[u]; ~i; i=e[i].next) + { + int v = e[i].to; + if(dep[v] != -1) + continue; + que[rear++] = v; + if(rear == MAXN) + rear = 0; + dep[v] = dep[u] + 1; + ++gap[dep[v]]; + } + } + } + +public: + void init(int n,int m) + { + cnt = 0; + memset(head,-1,sizeof(head)); + this -> n = n; + this -> m = m; + } + + int SAP(int st,int ed) + { + int res = 0; + bfs(st,ed); + int cur[MAXN]; + int S[MAXN]; + int top = 0; + memcpy(cur,head,sizeof(head)); + int u = st; + int i; + while(dep[st] < node) + { + if(u == ed) + { + int temp = INF; + int inser; + for(i=0; i e[S[i]].cap) + { + temp = e[S[i]].cap; + inser = i; + } + } + for(i=0; i dep[e[i].to]) + { + Min = dep[e[i].to]; + cur[u] = i; + } + } + --gap[dep[u]]; + dep[u] = Min+1; + ++gap[dep[u]]; + if(u != st) + u = e[S[--top]].from; + } + } + return res; + } + + void buildGraph() + { + node = n + 1; + } +} sap; diff --git "a/\347\275\221\347\273\234\346\265\201/\346\234\200\345\244\247\346\235\203\351\227\255\345\220\210\345\255\220\345\233\276.cpp" "b/\347\275\221\347\273\234\346\265\201/\346\234\200\345\244\247\346\235\203\351\227\255\345\220\210\345\255\220\345\233\276.cpp" new file mode 100644 index 0000000..c61b06c --- /dev/null +++ "b/\347\275\221\347\273\234\346\265\201/\346\234\200\345\244\247\346\235\203\351\227\255\345\220\210\345\255\220\345\233\276.cpp" @@ -0,0 +1,44 @@ + +/* + +建图方式: + +1.建立源点 s 和汇点 t; + +2.将源点 s 与所有权值为正的点相连,容量为对应的权值; + +3.将所有权值为负的点与汇点 t 相连,容量为对应权值的绝对值; + +4.权值为 0 的点不做处理; + +5.同时将原图中的边(原有的边)容量设置为 INF 。 + +*/ + +/* + +正确性证明: + +> 引理1.最小割一定是简单割。 + +> 证明: + 1.割 (S,T) 中每一条割边都与 s 或者 t 关联,这样的割叫做简单割。 + 2.将图中所有与 s 相连的点放入割集就可以得到一个割,且这个割的大小不为正无穷。 + 3.而最小割一定小于等于这个割,所以最小割一定不包含无穷大的边。 + 4.因此最小割一定简单割。 + +> 引理2. 简单割一定和一个闭合子图对应 + +> 证明: + 1.闭合子图 V 和源点 s 构成 S 集,其余点和汇点 t 构成 T 集。 + 2.证明闭合子图是简单割:若闭合子图对应的割 (S,T) 不是简单割,则存在一条边 (u,v),u∈S,v∈T,且c(u,v)=∞。说明 u 的后续节点 v 不在 S 中,矛盾。 + 3.再证明简单割是闭合子图:对于 V 中任意一个点 u,u∈S。u 的任意一条出边 c(u,v)=∞,不会在简单割的割边集中,因此 v 不属于 T,v∈S。所以V的所有点均在 S 中,因此 S-s 是闭合子图。 + +> 由上面两个引理可以知道,最小割也对应了一个闭合子图,接下来证明最小割就是最大权的闭合子图。 + 1.(割的容量 C(S,T)) = (T 中所有正权点的权值之和) + (S 中所有负权点的权值绝对值之和)。 + 2.(闭合子图的权值 W) = (S中所有正权点的权值之和) - (S 中所有负权点的权值绝对值之和)。 + 3.则(C(S,T)+W) = (T 中所有正权点的权值之和) + (S 中所有正权点的权值之和) = (所有正权点的权值之和)。 + 4.所以 W = (所有正权点的权值之和) - C(S,T)。 + 5.由于所有正权点的权值之和是一个定值,那么割的容量越小,W 也就越大。因此当 C(S,T) 取最小割时,W 也就达到了最大权。 + +*/ diff --git "a/\347\275\221\347\273\234\346\265\201/\346\234\200\345\260\221\346\234\200\345\260\217\345\211\262\350\276\271\346\225\260.cpp" "b/\347\275\221\347\273\234\346\265\201/\346\234\200\345\260\221\346\234\200\345\260\217\345\211\262\350\276\271\346\225\260.cpp" new file mode 100644 index 0000000..f75f82a --- /dev/null +++ "b/\347\275\221\347\273\234\346\265\201/\346\234\200\345\260\221\346\234\200\345\260\217\345\211\262\350\276\271\346\225\260.cpp" @@ -0,0 +1,35 @@ + +/* + +最小割性质:最小割边一定满流,满流的不一定是最小割边。 + +*/ + +/* + +1.建边:每条边权 w = w * (MAXE + 1) + 1 (因为加上 1 之后跑出来的最大流必定是边数最小的); + +2.得到的最大流为 max_flow / (MAXE + 1) (因为即使所有的边都算上,也只是多了 E 条边,除以 (E + 1) 后完全不影响结果)。 + +3.最小的割边数是 max_flow % (E + 1) ,即把全部的 1 算上也只有 E,对 (E + 1) 取余后就是最小的边数。 + +注:另一种“跑一次网络流以后修改满流边容量为 1,其他边为 INF ”的算法是假算法。原因:最小割边一定满流,满流的不一定是最小割边。 + +*/ + +void buildGraph() +{ + while(m--) //m为边数 + { + int u,v,w; + scanf("%d%d%d",&u,&v,&w); + addEdge(u,v,w*(MAXE+1)+1); + } +} + +void solve() +{ + buildGraph(); + printf("%d\n",maxFlow()%(MAXE+1)); //求出的结果就是最少最小割边数 + //printf("%d\n",SAP(s,t)%(MAXE+1)); +} diff --git "a/\350\256\241\347\256\227\345\207\240\344\275\225/A. \347\202\271\343\200\201\345\220\221\351\207\217\343\200\201\347\233\264\347\272\277\344\270\216\347\272\277\346\256\265\347\233\270\345\205\263\347\256\227\346\263\225.cpp" "b/\350\256\241\347\256\227\345\207\240\344\275\225/A. \347\202\271\343\200\201\345\220\221\351\207\217\343\200\201\347\233\264\347\272\277\344\270\216\347\272\277\346\256\265\347\233\270\345\205\263\347\256\227\346\263\225.cpp" new file mode 100644 index 0000000..527691b --- /dev/null +++ "b/\350\256\241\347\256\227\345\207\240\344\275\225/A. \347\202\271\343\200\201\345\220\221\351\207\217\343\200\201\347\233\264\347\272\277\344\270\216\347\272\277\346\256\265\347\233\270\345\205\263\347\256\227\346\263\225.cpp" @@ -0,0 +1,442 @@ +//计算几何模板——点、向量、直线与线段相关算法 + +/** +目录: +#A1.点的定义 +#A2.向量的基本运算 +#A3.直线、线段定义 +#A4.两直线交点 +#A5.点到直线的距离 +#A6.点到线段的距离 +#A7.点在直线上的投影 +#A8.判断点是否在线段上 +#A9.线段相交判定 +#A10.两点式转一般式 Ax + By + C = 0 +#A11.判断直线和线段相交 +#A12.点的极角排序 +#A13.分治法求平面最近点对 +**/ + + +/** +#A1.点的定义 +需要条件:无 +**/ +#define Vector Point + +typedef double Type; + +inline int dcmp(double x) +{ + return (x > EPS) - (x < -EPS); +} + +//点的定义 +struct Point +{ + Type x, y; + //int belong; //属于哪一个圆 + Point(Type x = 0, Type y = 0) : x(x), y(y) {} + + Vector operator + (const Vector& rhs) const + { + return Vector(x + rhs.x, y + rhs.y); + } + Vector operator - (const Point& rhs) const + { + return Vector(x - rhs.x, y - rhs.y); + } + Vector operator * (Type p) const + { + return Vector(x * p, y * p); + } + Vector operator / (Type p) const + { + return Vector(x / p, y / p); + } + bool operator < (const Point& rhs) const + { + return dcmp(x - rhs.x) < 0 || (dcmp(x - rhs.x) == 0 && dcmp(y - rhs.y) < 0); + } + /* + bool operator < (const Point& rhs) const + { + return x < rhs.x || (x == rhs.x && y < rhs.y); + } + */ + bool operator == (const Point& rhs) const + { + return dcmp(x - rhs.x) == 0 && dcmp(y - rhs.y) == 0; + } + bool operator > (const Point& rhs) const + { + return !(*this < rhs || *this == rhs); + } + bool operator >= (const Point& rhs) const + { + return !(*this < rhs); + } + bool operator <= (const Point& rhs) const + { + return (*this < rhs || *this == rhs); + } + double operator * (const Vector& rhs) const //点积 + { + return x * rhs.x + y * rhs.y; + } + double operator ^ (const Vector& rhs) const //叉积 + { + return x * rhs.y - y * rhs.x; + } + + void read() + { + scanf("%lf%lf", &x, &y); + } + + void print() const + { + printf("(%f, %f)", x, y); + } +}; + + +/** +#A2.向量的基本运算 +需要条件:A1 +**/ +//距离 +Type Length(Point p1, Point p2) +{ + Type x = p1.x - p2.x, y = p1.y - p2.y; + return sqrt(x * x + y * y); +} + +//向量的模 +Type Length(Vector v) +{ + return sqrt(v * v); +} + +//叉积 +Type Cross(Vector v1, Vector v2) +{ + return v1.x * v2.y - v1.y * v2.x; +} + +Type Cross(Point &p1, Point &p2, Point &p3) +{ + return Cross(p1 - p3, p2 - p3); +} + +//点积 +Type Dot(Vector v1, Vector v2) +{ + return v1.x * v2.x + v1.y * v2.y; +} + +//向量的夹角 a*b=|a||b|cosα +Type Angle(Vector v1, Vector v2) +{ + return acos(v1 * v2 / Length(v1) / Length(v2)); +} + +//AB x AC组成的空间 +double Area2(Point p1, Point p2, Point p3) +{ + return (p2 - p1) ^ (p3 - p1); +} + +//向量逆时针旋转rad弧度 +Vector Rotate(Vector v, double rad) +{ + return Vector(v.x * cos(rad) - v.y * sin(rad), v.x * sin(rad) + v.y * cos(rad)); +} + +//计算A的法线(A不是0向量) +//左转90° 长度归一化 +Vector Normal(Vector v) +{ + Type l = Length(v); + return Vector(-v.y / l, v.x / l); +} + +//单位向量 +Vector ToUnit(Vector v) +{ + Type l = Length(v); + return Vector(v.x/l,v.y/l); +} + +//计算向量极角(需要头文件) +double Angle(Vector v) +{ + return atan2(v.y, v.x); +} + + +/** +#A3.直线、线段定义(它的左边是对应的半平面) +需要条件:A1 +**/ +struct Line +{ + Point a,b; //直线(线段)的两个端点(线段的时候可把a当作起点) + Vector v; //方向向量,v = b - a + //double ang;//极角 + Line() {} + Line(Point a,Point b):a(a),b(b) + { + v = b - a; /*ang = atan2(v.y, v.x);*/ + } + Line translation(double d) + { + return Line(a + Normal(v)*d, v); + } + bool operator < (const Line& rhs) const + { + //根据原点极角排序(小的在前;极角相同,长度小的在前) + //return ang < L.ang; + if (v.y * rhs.v.y > 0) //同上同下 + { + if ((v ^ rhs.v) != 0) + return (v ^ rhs.v) > 0; + return Length(v) > Length(rhs.v); //极角相同,长的小 + } + if (v.y * rhs.v.y < 0) + return v.y < 0; //一上一下 + if (v.y == 0) + { + if (rhs.v.y == 0) + { + if (v.x * rhs.v.x < 0) + return v.x > rhs.v.x; + return Length(v) > Length(rhs.v); //极角相同长的小 + } + if (v.x > 0) + return rhs.v.y > 0; + return false; + } + if (rhs.v.x > 0) + return v.y < 0; + return true; + } +}; + +typedef Line Segment; + + +/** +#A4.两直线交点 +需要条件:A1,A2,A3 +**/ +Point LineIntersection(Line &L1,Line &L2) +{ + Vector u = L1.a - L2.a; + Vector v1 = L1.b - L1.a, v2 = L2.b - L2.a; + if(dcmp(v1 ^ v2) == 0) + { + if(dcmp(u ^ v1)) + return Point(-INF,-INF);//平行 + else + return Point(-INF,-INF);//在一条线上 + } + Type t = (v2 ^ u) / (v1 ^ v2); + return L1.a + v1 * t; +} + + +/** +#A5.点到直线的距离 +需要条件:A1,A2,A3 +**/ +Type DistanceToLine(Point p,Line L) +{ + Vector v1 = L.b - L.a, v2 = p - L.a; + return fabs(v1 ^ v2) / Length(v1); +} + + +/** +#A6.点到线段的距离 +需要条件:A1,A2,A3 +**/ +Type DistanceToSegment(Point p,Segment seg) +{ + if(seg.a == seg.b) + return Length(p,seg.a); + Vector v1 = seg.b - seg.a, v2 = p - seg.a, v3 = p - seg.b; + if(dcmp(v1 * v2) < 0) + return Length(v2); + else if(dcmp(v1 * v3) > 0) + return Length(v3); + else + return fabs(v1 ^ v2) / Length(v1); +} + + +/** +#A7.点在直线上的投影 +需要条件:A1,A2,A3 +**/ +Point LineProjection(Point p,Line L) +{ + Vector v = L.b - L.a; + return L.a + v * (v * (p - L.a) / (v * v)); +} + + +/** +#A8.判断点是否在线段上 +需要条件:A1,A2,A3 +**/ +bool OnSegment(Point &p,Segment& S) +{ + //小于0不包含端点,小于等于包含端点 + return dcmp((S.a-p)^(S.b-p)) == 0 && dcmp((S.a-p)*(S.b-p)) <= 0; +} + +/** +#A9.线段相交判定  +需要条件:A1,A2,A3 +**/ +/*线段规范相交*/ +//两条线段恰有一个不是端点的公共点。(即如果一条线段的一个端点恰在另一条线段上则不视为相交;如果两条线段部分重合,也不视为相交。) +bool SegmentProperIntersect(Segment &s1,Segment& s2) +{ + Type c1 = (s1.b - s1.a) ^ (s2.a - s1.a), c2 = (s1.b - s1.a) ^ (s2.b - s1.a), + c3 = (s2.b - s2.a) ^ (s1.a - s2.a), c4 = (s2.b - s2.a) ^ (s1.b - s2.a); + return dcmp(c1) * dcmp(c2) < 0 && dcmp(c3) * dcmp(c4) < 0; +} + +/*线段不规范相交(使用的时候结合线段规范相交的函数一起判断)*/ +//两条线段存在公共部分。(上述两种情况都可视为非规范相交) +bool SegmentNotProperIntersect(Segment& s1,Segment& s2) +{ + return OnSegment(s1.a,s2) || OnSegment(s1.b,s2) || OnSegment(s2.a,s1) || OnSegment(s2.b,s1); +} + + +/** +#A10.两点式转一般式 Ax + By + C = 0 +需要条件:A1,A2,A3 +**/ +///模板待测!!! +void toNormalLine(Line &L,Type &A,Type& B,Type &C) +{ + A = L.a.y - L.b.y; + B = L.b.x - L.a.x; + C = -B * L.a.y - A * L.a.x; +} + + +/** +#A11.判断直线和线段相交 +需要条件:A1,A2,A3 +**/ +bool LineIntersectSegment(Line &L,Segment &S) +{ + Vector a(S.a-L.a); + Vector b(S.b-L.a); + Vector c(L.b-L.a); + int dcmpA = dcmp(c ^ a); + int dcmpB = dcmp(c ^ b); + return dcmpA * dcmpB <= 0; +} + + +/** +#A12.点的极角排序 +需要条件:A1,A2 +**/ +/*A12.1常用版*/ +//利用叉积进行极角排序,极角相同的,距离原点近的小 +int pos; +Point p[100]; +bool AngleCmp(Point a,Point b) +{ + Type temp = (a - p[pos]) ^ (b - p[pos]); + if(dcmp(temp) == 0) + return Length(p[pos],a) < Length(p[pos],b); + else if(dcmp(temp) < 0) + return false; + else + return true; +} + +/*A12.2*/ +//利用arctan计算极角大小排序(范围[-180,180]) +bool AngleCmp(const Point& a,const Point& b) +{ + return atan2(a.y, a.x) < atan2(b.y, b.x); +} + +/*A12.3*/ +//利用象限加上极角,叉积排序 +bool AngleCmp(const Point &a,const Point &b) //先按象限排序,再按极角排序,再按远近排序 +{ + if(a.y == 0 && b.y == 0 && a.x * b.x <= 0) + return a.x > b.x; + if(a.y == 0 && a.x >= 0 && b.y != 0) + return true; + if(b.y == 0 && b.x >= 0 && a.y != 0) + return false; + if(b.y*a.y <= 0) + return a.y>b.y; + Point O; + O.y = O.x = 0; + return (a - O) ^ (b - O) > 0 || ((a - O) ^ (b - O) == 0 && a.x < b.x); +} + + +/** +#A13.分治法求平面最近点对 +需要条件:A1,A2 +**/ +//先对点按照先x后y进行排序,然后调用closestPair(l, r)进行扫描即可 +Point p[MAXN]; +int tmp[MAXN]; + +bool cmp(Point a, Point b) //对点先x坐标后y坐标排序 +{ + if(a.x == b.x) + return a.y < b.y; + return a.x < b.x; +} + +bool cmpy(int idxa, int idxb) //对y坐标进行排序 +{ + return p[idxa].y < p[idxb].y; +} + +double closestPair(int left, int right) +{ + double d = INF; + if(left == right) + return d; + if(left + 1 == right) + return Length(p[left], p[right]); + int mid = (left + right) >> 1; + double d1 = closestPair(left, mid); + double d2 = closestPair(mid + 1, right); + d = min(d1, d2); + int k = 0; + //分离出宽度为d的区间 + for(int i = left; i <= right; i++) + { + if(fabs(p[mid].x - p[i].x) <= d) + tmp[k++] = i; + } + sort(tmp, tmp + k, cmpy); + //线性扫描 + for(int i = 0; i < k; i++) + { + for(int j = i + 1; j < k && p[tmp[j]].y - p[tmp[i]].y < d; j++) + { + double d3 = Length(p[tmp[i]], p[tmp[j]]); + if(d > d3) + d = d3; + } + } + return d; +} diff --git "a/\350\256\241\347\256\227\345\207\240\344\275\225/B. \345\234\206\347\233\270\345\205\263\347\256\227\346\263\225.cpp" "b/\350\256\241\347\256\227\345\207\240\344\275\225/B. \345\234\206\347\233\270\345\205\263\347\256\227\346\263\225.cpp" new file mode 100644 index 0000000..5f4f632 --- /dev/null +++ "b/\350\256\241\347\256\227\345\207\240\344\275\225/B. \345\234\206\347\233\270\345\205\263\347\256\227\346\263\225.cpp" @@ -0,0 +1,414 @@ +//计算几何模板——圆相关算法 + +/** +目录: +#B1.圆的定义 +#B2.判断点在圆内 +#B3.直线与圆的交点 +#B4.线段与圆相交判定 +#B5.线段和圆的交点 +#B6.两圆交点 +#B7.两圆面积交 +#B8.把角变成0~2PI范围内 +#B9.求圆过某一点的所有切线 +#B10.求两圆的公切线 +#B11.三角形外接圆 +#B12.三角形内切圆 +#B13.过某一点与直线相切的圆 +#B14.与两条直线相切的圆 +#B15.与两圆相切的圆 +**/ + + +/** +#B1.圆的定义 +需要条件:A1 +**/ +struct Circle +{ + Point p; + Type r; + Circle(Point p,Type r):p(p),r(r) {} + Circle() {} + Point polarCoordinates(double a) //求圆边界上某个点相对于圆心的极角坐标 + { + return Point(p.x + cos(a) * r, p.y + sin(a) * r); + } + void read() + { + p.read(); + scanf("%lf", &r); + } +}; + + +/** +#B2.判断点在圆内(圆周上不算) +需要条件:A1,B1 +**/ +bool isInCircle(Point p, Circle C) +{ + return dcmp((p - C.p) * (p - C.p) - C.r * C.r) < 0; +} + + +/** +#B3.直线与圆的交点 +需要条件:A1,B1 +**/ +//t1,t2为两个记录变量的参数,使用该函数前定义即可 +int getLineCircleIntersection(Line L,Circle C,double& t1,double& t2,vector& sol) +{ + //t1,t2为从L.p出发的长度,sol保存结果,返回值为交点个数 + double a = L.v.x, b = L.a.x - C.p.x, + c = L.v.y, d = L.a.y - C.p.y; + double e = a * a + c * c, f = 2 * (a * b + c * d), + g = b * b + d * d - C.r * C.r; + double delta = f * f - 4 * e * g; //判别式 + if(dcmp(delta) < 0) //相离 + return 0; + if(dcmp(delta) == 0) //相切 + { + t1 = t2 = -f / (2 * e); + sol.PB(L.a + v * t1); + return 1; + } + //相交 + t1 = (-f - sqrt(delta)) / (2 * e); + if(dcmp(t1-1) <= 0 && dcmp(t1) >= 0) //这条判断表示线段 + sol.PB(L.a + L.v * t1); + t2 = (-f + sqrt(delta)) / (2 * e); + if(dcmp(t2-1) <= 0 && dcmp(t2) >= 0) //这条判断表示线段 + sol.PB(L.a + L.v * t2); + return 2; +} + +void getLineCircleIntersection(Line L,Circle C,vector& ret) +{ + Vector v = L.b - L.a; + Type a = v.x, b = L.a.x - C.p.x, c = v.y, d = L.a.y - C.p.y; + Type e = a * a + c * c, f = 2 * (a * b + c * d), g = b * b + d * d - C.r * C.r; + Type delta = f * f - 4 * e * g; + Type t1, t2; + if(dcmp(delta) < 0) //相离 + return; + if(dcmp(delta) == 0) //相切 + { + t1 = t2 = -f / (2 * e); + ret.PB(L.a + v * t1); + } + else + { + t1 = (-f - sqrt(delta)) / (2 * e); + if(dcmp(t1-1) <= 0 && dcmp(t1) >= 0) //这条判断表示线段 + ret.PB(L.a + v * t1); + t2 = (-f + sqrt(delta)) / (2 * e); + if(dcmp(t2-1) <= 0 && dcmp(t2) >= 0) //这条判断表示线段 + ret.PB(L.a + v * t2); + } +} + + +/** +#B4.线段与圆相交判定(相切不算) +需要条件:A1,A2,B1,B3 +**/ +///模板待测!!! +//线段不考虑端点 +bool CircleIntersectSegment(Segment s,Circle C) +{ + double t1, t2; + vector sol; //线段与圆的交点 + int c = getLineCircleIntersection(Line(s.a,s.b),C,t1,t2,sol); + if(c <= 1) + return false; + if(dcmp(t1) > 0 && dcmp(t1-1) < 0) + return true; //端点在圆上 + if(dcmp(t2) > 0 && dcmp(t2-1) < 0) + return true; + return false; +} + +//##28##: 线段和圆的交点 结果保存在sol中 +//需要条件: 1 2 10 12 14 +/** +#B5.线段和圆的交点 +需要条件:A1,A2,A3,B1,B3 +**/ +///模板待测!!! +//结果保存在sol中 +int getSegmentCircleIntersection(Line L,Circle C,vector& sol) +{ + double t1, t2; + vector tmp; + int m = getLineCircleIntersection(L,C,t1,t2,tmp); + if(m == 0) + return 0; + if(m <= 2) + { + if(dcmp((L.a-tmp[0])*(L.b-tmp[0])) <= 0) + sol.PB(tmp[0]); + if(m == 1) + return sol.size(); + } + if(dcmp((L.a-tmp[1])*(L.b-tmp[1])) <= 0) + sol.PB(tmp[1]); + return sol.size(); +} + + +/** +#B6.两圆交点 +需要条件:A1,A2,B1 +**/ +int getTwoCirclesIntersection(Circle c1, Circle c2, vector &ret) +{ + Type d = Length(c1.p, c2.p); + if(dcmp(d) == 0) + { + if(dcmp(c1.r - c2.r) == 0) + return -1; //两圆重合 + return 0; //内含 + } + if(dcmp(c1.r + c2.r - d) < 0) + return 0; //相离 + if(dcmp(fabs(c1.r - c2.r) - d) > 0) + return 0; //内含 + Type a = Angle(c2.p - c1.p); + Type da = acos((c1.r * c1.r + d * d - c2.r * c2.r) / (2 * c1.r * d)); + Point p1 = c1.polarCoordinates(a - da), p2 = c1.polarCoordinates(a + da); + ret.PB(p1); + if(p1 == p2) + return 1; + ret.PB(p2); + return 2; +} + +//两圆相交的交点相对于圆1圆心的极角保存在rad中 +///模板待测!!! +void getTwoCirclesIntersection(Circle C1,Circle C2,vector& rad) +{ + double d = Length(C1.p-C2.p); + if(dcmp(d) == 0) + return; //不管是内含还是重合,都不相交 + if(dcmp(C1.r+C2.r-d) < 0) + return; + if(dcmp(fabs(C1.r-C2.r)-d) > 0) + return; + double a = Angle(C2.p-C1.p); + double da = acos((C1.r*C1.r+d*d-C2.r*C2.r)/(2*C1.r*d)); + rad.PB(NormalizeAngle(a-da)); //相交弧为从减到加(逆时针 + rad.PB(NormalizeAngle(a+da)); +} + + +/** +#B7.两圆面积交 +需要条件:A2,B1 +**/ +Type getInterArea(Circle a, Circle b) +{ + Type dis = Length(a.p, b.p); + if(dcmp(a.r + b.r - dis) <= 0) + return 0; + if(dcmp(abs(a.r - b.r) - dis) >= 0) + { + Type r = min(a.r, b.r); + return PI * r * r; + } + Type cosX = (dis * dis + a.r * a.r - b.r * b.r) / (2 * dis * a.r); + Type X = acos(cosX); + Type cosY = (dis * dis + b.r * b.r - a.r * a.r) / (2 * dis * b.r); + Type Y = acos(cosY); + return a.r * a.r * X + b.r * b.r * Y - dis * a.r * sin(X); +} + + +/** +#B8.把角变成0~2PI范围内 +需要条件:无 +**/ +///模板待测!!! +//负数也可以使用 +double NormalizeAngle(double rad) +{ + return rad - 2 * PI * floor(rad / (2 * PI)); +} + + +/** +#B9.求圆过某一点的所有切线 +需要条件:A1,A2,B1 +**/ +void getTangentPoint(Point p, Circle c, vector &v) +{ + double dis = Length(p, c.p); + double base = Angle(p - c.p); + double ang = acos(c.r / dis); + v.PB(c.polarCoordinates(base - ang)); + v.PB(c.polarCoordinates(base + ang)); +} + +///模板待测!!! +//返回切线条数,也可以把int改成void不返回切线条数 +int TangentLineThroughPoint(Circle c,Point p,vector &v) +{ + Vector u = c.p - p; + Type dist = Length(u); + if(dist < c.r) + return 0; + if(dcmp(dist-c.r) == 0) + { + Vector vt = Rotate(u,PI/2); + v.PB(Line(p,p+vt)); + return 1; + } + else if(dcmp(dist-c.r) > 0) + { + Type ang = asin(c.r/dist); + Vector v0 = Rotate(u,-ang), v1 = Rotate(u,ang); + v.PB(Line(p,p+v0)); + v.PB(Line(p,p+v1)); + return 2; + } +} + + +/** +#B10.求两圆的公切线 +需要条件:A1,B1 +**/ +//返回切线条数,v为所有的切线,第一个点是A上的切点,第二个点是B上的切点 +int getTangents(Circle A, Circle B, vector &v) +{ + Point ta[5], tb[5]; + Point *a = ta, *b = tb; + if(A.r < B.r) + { + swap(A, B); + swap(a, b); + } + int cnt = 0; + Type d2 = sqr(Length(A.p, B.p)); + Type rdiff = A.r - B.r; + Type rsum = A.r + B.r; + if(dcmp(d2 - rdiff * rdiff) < 0) + return 0; //内含 + Vector va = B.p - A.p; + Type base = atan2(va.y, va.x); + if(dcmp(d2) == 0 && dcmp(A.r - B.r) == 0) + return -1; //无限条切线 + if(dcmp(d2 - rdiff * rdiff) == 0) //内切 + { + a[cnt] = A.getPoint(base); + b[cnt++] = B.getPoint(base); + v.PB(Line(ta[0], tb[0])); + return 1; + } + //有外公切线 + Type ang = acos((A.r - B.r) / sqrt(d2)); + a[cnt] = A.getPoint(base + ang); + b[cnt++] = B.getPoint(base + ang); + a[cnt] = A.getPoint(base - ang); + b[cnt++] = B.getPoint(base - ang); + if(dcmp(d2 - rsum * rsum) == 0) //一条内公切线 + { + a[cnt] = A.getPoint(base); + b[cnt++] = B.getPoint(PI + base); + } + else if(dcmp(d2 - rsum * rsum) > 0) + { + Type ang = acos((A.r + B.r) / sqrt(d2)); + a[cnt] = A.getPoint(base + ang); + b[cnt++] = B.getPoint(PI + base + ang); + a[cnt] = A.getPoint(base - ang); + b[cnt++] = B.getPoint(PI + base - ang); + } + for(int i = 0; i < cnt; i++) + v.PB(Line(ta[i], tb[i])); + return cnt; +} + + +/** +#B11.三角形外接圆 +需要条件:A1,A2,B1 +**/ +Circle TriangleCircumscribedCircle(Point p1, Point p2, Point p3) +{ + double Bx = p2.x - p1.x, By = p2.y - p1.y; + double Cx = p3.x - p1.x, Cy = p3.y - p1.y; + double D = 2 * (Bx * Cy - By * Cx); + double cx = (Cy * (Bx * Bx + By * By) - By * (Cx * Cx + Cy * Cy)) / D + p1.x; + double cy = (Bx * (Cx * Cx + Cy * Cy) - Cx * (Bx * Bx + By * By)) / D + p1.y; + Point p = Point(cx, cy); + return Circle(p, Length(p1, p)); +} + + +/** +#B12.三角形内切圆 +需要条件:A1,A2,A5,B1 +**/ +Circle TriangleInscribedCircle(Point p1, Point p2, Point p3) +{ + double a = Length(p2, p3); + double b = Length(p1, p3); + double c = Length(p1, p2); + Point p = (p1 * a + p2 * b + p3 * c) / (a + b + c); + return Circle(p, DistanceToLine(p, Line(p1, p2))); +} + + +/** +#B13.过某一点与直线相切的圆(半径为r) +需要条件:A1,A2,A5,B1,B3 +**/ +///模板待测!!! +//返回所求圆的圆心 +vector CircleThroughPointTangentLine(Point p,Line L,double r) +{ + vector ans; + double t1, t2; + getLineCircleIntersection(L.translation(-r),Circle(p,r),t1,t2,ans); + getLineCircleIntersection(L.translation(r),Circle(p,r),t1,t2,ans); + return ans; +} + + +/** +#B14.与两条直线相切的圆(半径为r) +需要条件:A1,A2,A3,A4 +**/ +///模板待测!!! +//返回所求圆的圆心 +vector CircleTangent2Lines(Line a,Line b,double r) +{ + vector ans; + Line L1 = a.translation(-r), L2 = a.translation(r); + Line L3 = b.translation(-r), L4 = b.translation(r); + ans.PB(LineIntersection(L1,L3)); + ans.PB(LineIntersection(L1,L4)); + ans.PB(LineIntersection(L2,L3)); + ans.PB(LineIntersection(L2,L4)); + return ans; +} + + +/** +#B15.与两圆相切的圆(半径为r) +需要条件:A1,A2,B1,B6 +**/ +///模板待测!!! +//返回所求圆的圆心 +vector CircleTangent2Circles(Circle c1, Circle c2, double r) +{ + vector ans; + Vector v = c2.c - c1.c; + double dist = Length(v); + int d = dcmp(dist-c1.r-c2.r-r*2); //两圆相距太远 + if(d > 0) + return ans; + getTwoCirclesIntersection(Circle(c1.c, c1.r+r),Circle(c2.c, c2.r+r),ans); + return ans; +} diff --git "a/\350\256\241\347\256\227\345\207\240\344\275\225/C. \345\244\232\350\276\271\345\275\242\345\222\214\345\207\270\345\214\205\347\233\270\345\205\263\347\256\227\346\263\225.cpp" "b/\350\256\241\347\256\227\345\207\240\344\275\225/C. \345\244\232\350\276\271\345\275\242\345\222\214\345\207\270\345\214\205\347\233\270\345\205\263\347\256\227\346\263\225.cpp" new file mode 100644 index 0000000..7cedeaf --- /dev/null +++ "b/\350\256\241\347\256\227\345\207\240\344\275\225/C. \345\244\232\350\276\271\345\275\242\345\222\214\345\207\270\345\214\205\347\233\270\345\205\263\347\256\227\346\263\225.cpp" @@ -0,0 +1,311 @@ +//计算几何模板——多边形和凸包相关算法 + +/** +目录: +#C1.多边形定义 +#C2.多边形的有向面积 +#C3.点在多边形内判定 +#C4.多边形重心 +#C5.圆和三角形相交的面积(三角形的一个顶点为圆心) +#C6.圆和多边形相交的面积(利用三角剖分) +#C7.返回圆盘是否与多边形相交 +#C8.删除平面的三点共线 +#C9.有向直线切割多边形 +#C10.求点集凸包 +#C11.判断是否是凸包(向量法判断) +#C12.判断圆是否在多边形内 +**/ + + +/** +#C1.多边形定义 +需要条件:A1 +**/ +typedef vector Polygon; //组成该平面的逆时针点集 + + +/** +#C2.多边形的有向面积(点逆时针旋转为正向,顺时针将求出负值) +需要条件:A1,C1 +**/ +double PolygonArea(Polygon &poly) +{ + if(poly.size() == 0) + return 0; + double area = 0; + for(int i=1; i 0 && d1 <= 0 && d2 > 0) + wn++; + if(k < 0 && d2 <= 0 && d1 > 0) + wn--; + } + if(wn) + return 1; //在多边形内部 + return 0; //在多边形外部 +} + + +/** +#C4.多边形重心 +需要条件:A1,C1 +**/ +//调用之前应先求得凸包 +Point getPolygonCenterOfGravity(Polygon &poly) +{ + int n = poly.size(); + Point ret; + double area = 0, area2; + for(int i=1; i p, tmp; + p.PB(a); + Line l(a, b); + if(getLineCircleIntersection(l, c, tmp) == 2) //直线和圆的位置关系 0:相离 1:相切 2:相交 + { + if(dcmp((a - tmp[0]) * (b - tmp[0])) < 0) + p.PB(tmp[0]); + if(dcmp((a - tmp[1]) * (b - tmp[1])) < 0) + p.PB(tmp[1]); + } + p.PB(b); + if(sz(p) == 4 && dcmp((p[0] - p[1]) * (p[2] - p[1])) > 0) + swap(p[1], p[2]); + double res = 0.0; + for(int i = 0; i < sz(p) - 1; i++) + { + Vector v1 = p[i] - c.p, v2 = p[i + 1] - c.p; + if(dcmp(Length(v1) - c.r) > 0 || dcmp(Length(v2) - c.r) > 0) + { + double arg = Angle(v1, v2); + res += c.r * c.r * arg / 2.0; + } + else + res += fabs((v1 ^ v2) / 2.0); + } + return res; +} + + +/** +#C6.圆和多边形相交的面积(利用三角剖分) +需要条件:A1, C1, C5 +**/ +double CirclePolygonIntersectionArea(Circle c, Polygon &poly) +{ + double ret = 0; + for(int i = 0; i < sz(poly); i++) + { + Vector v1 = poly[i] - c.p, v2 = poly[(i + 1) % sz(poly)] - c.p; + ret += 1.0 * dcmp(v1 ^ v2) * CircleTriangleIntersectionArea(c, poly[i], poly[(i + 1) % sz(poly)]); + } + return fabs(ret); +} + + +/** +#C7.返回圆盘是否与多边形相交 +需要条件:A1,A2 7 10 12 13 14 15 C1,C3 +**/ +///模板待测!!! +bool DiscIntersectPolygon(Polygon poly,Point p,double R) +{ + if(isPointInPolygon(p,poly)) + return true; + if(isInCircle(poly[0],p,R)) + return true; + int n = poly.size(); + for(int i=0; iB切割多边形poly,返回“左侧”。 如果退化,可能会返回一个单点或者线段 +Polygon CutPolygon(Polygon& poly,Point A,Point B) +{ + Polygon newpoly; + int n = poly.size(); + for(int i = 0; i < n; i++) + { + Point C = poly[i]; + Point D = poly[(i+1)%n]; + if(dcmp((B-A)^(C-A)) >= 0) + newpoly.PB(C); + if(dcmp((B-A)^(C-D)) != 0) + { + Line l1 = Line(A,B); + Line l2 = Line(C,D); + Point ip = LineIntersection(l1,l2); + Segment seg = Segment(C,D); + if(OnSegment(ip,seg)) + newpoly.PB(ip); + } + } + return newpoly; +} + + +/** +#C10.Andrew算法求点集凸包 +需要条件:A1 +**/ +/*C10.1: 求得的凸包存在 vector ch 内*/ +//如果不希望在凸包的边上有输入点,把两个 <= 改成 < (说明:这里lrj可能写错了,应该是凸包边上无点:<= ;有点:<) +//如果不介意点集被修改,可以改成传递引用(不能修改就去掉&) +int ConvexHull(vector &p,vector &ch) +{ + sort(p.begin(),p.end()); //两个点比大小,先横坐标再纵坐标,升序 + int n = unique(p.begin(),p.end()) - p.begin();//删除重复点 + int m = 0; + ch.resize(n+1); + for(int i=0; i 1 && dcmp((ch[m-1]-ch[m-2])^(p[i]-ch[m-2])) <= 0) + m--; + ch[m++] = p[i]; //发现右边的点时删除前面的点,再更新 + } + int k = m; //下凸包点数,找上凸包时防止误删 + for(int i=n-2; i>=0; i--) + { + while(m > k && dcmp((ch[m-1]-ch[m-2])^(p[i]-ch[m-2])) <= 0) + m--; + ch[m++] = p[i]; + } + if(n > 1) + m--; + ch.resize(m); + return m; //返回的点集逆时针排序 +} + +/*C10.2: 求得的凸包存在 Point *ch 内*/ +//求凸包,如果不希望凸包边上有输入点,把<=改成< (说明:这里lrj可能写错了,应该是凸包边上无点:<= ;有点:<) +int ConvexHull(Point *p,int n,Point *ch) +{ + sort(p,p+n); + n = unique(p,p+n) - p; //删除重复点 + int m = 0; + for(int i=0; i 1 && dcmp((ch[m-1]-ch[m-2])^(p[i]-ch[m-2])) <= 0) + m--; + ch[m++] = p[i]; + } + int k = m; + for(int i=n-2; i>=0; i--) + { + while(m > k && dcmp((ch[m-1]-ch[m-2])^(p[i]-ch[m-2])) <= 0) + m--; + ch[m++] = p[i]; + } + if(n > 1) + m--; + return m; +} + + +/** +#C11.判断是否是凸包(向量法判断) +需要条件:A1 +**/ +bool isConvexHull(Point *p,int n) +{ + int flag = 0; //记录顺时针还是逆时针 + for(int i=0; i 0) + q = (q + 1) % n; + ans = max(ans,Length(p[i],p[q])); + ans = max(ans,Length(p[i+1],p[q+1])); + } + return ans; +} + + +/** +#D2.旋转卡壳求两个凸包的最近点对 +需要条件:A1,A2,A6,C9 +**/ +//p,q是两个凸包,np,nq分别是两个凸包的点数 +//使用时要调用min(RotatingCalipers(p,np,q,np),RotatingCalipers(q,nq,p,np)); +Type RotatingCalipers(Point *p,int np,Point *q,int nq) +{ + int sp = 0,sq = 0; + for(int i=0; i 0) + sq = i; + double tmp, ans = INF; + p[np] = p[0], q[nq] = q[0]; + for(int i = 0; i 0) + ans = min(ans,DistanceToSegment(q[sq],Segment(p[sp],p[sp+1]))); + else + { + Segment segp(p[sp],p[sp+1]), segq(q[sq],q[sq+1]); + ans = min(ans,DistanceToSegment(p[sp],segq)); + ans = min(ans,DistanceToSegment(p[sp+1],segq)); + ans = min(ans,DistanceToSegment(q[sq],segp)); + ans = min(ans,DistanceToSegment(q[sq+1],segp)); + } + sp = (sp + 1) % np; + } + return ans; +} + + +/** +#D3.旋转卡壳求平面点集构成的最大三角形面积 +需要条件:A1,A2,C9 +**/ +//高级板,速度较快 +Type RotatingCalipers(Point *p,int n) +{ + Type ans = 0; + int j,k; + for(int i=0; i 0) + k = (k + 1) % n; + while(i != j && k != i) + { + ans = max(ans,Cross(p[i],p[j],p[k])); + while(dcmp(Cross(p[i],p[j],p[(k+1)%n])-Cross(p[i],p[j],p[k])) > 0) + k = (k + 1) % n; + j = (j + 1) % n; + } + } + return ans / 2.0; +} + +//保守模板,速度较慢 +Type RotatingCalipers(Point *p,int n) +{ + Type ans = 0; + for(int i=0; i 0) + k = (k + 1) % n; + ans = max(ans,Cross(p[i],p[j],p[k])); + } + } + return ans / 2.0; +} + + +/** +#D4.旋转卡壳求平面点集构成的最大四边形面积 +需要条件:A1,A2,C9 +**/ +Type RotatingCalipers(Point *p,int n) +{ + Type ans = 0; + p[n] = p[0]; + for(int i=0; i 0) + q1 = (q1 + 1) % n; + while(q2!=i && dcmp(fabs(Cross(p[i],p[j],p[q2+1]))-fabs(Cross(p[i],p[j],p[q2]))) > 0) + q2 = (q2 + 1) % n; + ans = max(ans,fabs(Cross(p[i],p[j],p[q1]))+fabs(Cross(p[i],p[j],p[q2]))); + } + } + return ans / 2.0; +} + + +/** +#D5.旋转卡壳求包围点的最小面积(周长)的矩形 +需要条件:A1,A2,A5,C9 +**/ +//p是凸包,n是凸包点数 +pair RotatingCalipers(Point *p,int n) +{ + if(n<3) //避免精度问题,否则1个点的时候可能不会返回0 + return MP(0,0); + p[n] = p[0]; + Type minS = 1e99, minC = 1e99; //最小的矩形面积和矩形周长 + int l = 1, r = 1, u = 1; + for(int i=0; i 0) //左边 + l++; + Type w = v * (p[r%n] - p[i]) - v * (p[l%n] - p[i]); + Type h = DistanceToLine(p[u%n],Line(p[i],p[i+1])); + minS = min(minS,w*h); + minC = min(minC,2*(w+h)); + } + return MP(minS,minC); +} diff --git "a/\350\256\241\347\256\227\345\207\240\344\275\225/E. \345\215\212\345\271\263\351\235\242\344\272\244.cpp" "b/\350\256\241\347\256\227\345\207\240\344\275\225/E. \345\215\212\345\271\263\351\235\242\344\272\244.cpp" new file mode 100644 index 0000000..b7a6198 --- /dev/null +++ "b/\350\256\241\347\256\227\345\207\240\344\275\225/E. \345\215\212\345\271\263\351\235\242\344\272\244.cpp" @@ -0,0 +1,126 @@ +//计算几何模板——半平面交 + +/** +目录: +#E1.半平面交 +**/ + + +/** +#E1.半平面交 +需要条件:A1,A2,A3,A4,C1 +**/ +///模板待测!!! +/*直线版模板*/ +//点p在有向直线L的左边(线上不算) +bool onLeft(const Line& L, const Point& p) +{ + return (L.v ^ (p-L.p)) > 0; +} +// 如果不介意边被修改 可以改为传引用 +Polygon HalfplaneIntersection(vector L) +{ + int n = L.size(); + sort(L.begin(), L.end()); //按极角排序 + int first, last; //双端队列的第一个元素和最后一个元素的下标 + vector p(n); //p[i]为q[i]和q[i+1]的交点 + vector q(n); //双端队列 + Polygon ans; //结果 + q[first=last=0] = L[0]; //双端队列初始化为只有一个半平面L[0] + for(int i=1; i 0; +} + +Point LineIntersection(DirLine &a,DirLine& b) +{ + Vector u = a.p - b.p; + Type t = Cross(b.v,u) / Cross(a.v,b.v); + return a.p + a.v * t; +} + +Point halfP[MAXN<<1]; +DirLine halfQ[MAXN<<1]; + +int HalfplaneIntersection(DirLine* l,int n,Point *poly) +{ + sort(l,l+n); + int head,tail; + DirLine *q = halfQ; //双端队列 + Point *p = halfP; //p[i]表示q[i]和q[i+1]的交点 + halfQ[head = tail = 0] = l[0]; + for(int i=1; i& V) 传入点集 + * addEdge(u, v) 添加u到v的变 u,v为点的序号 + * get_face(),得到如下东西 + * faces 保存每个面(面是由逆时针点构成) + * left[i] 每条边 左边的面的编号 + * area[i] 每个面的面积 + * 对于内部区域来说,无限面的各个顶点是顺时针的 + * 无限面多边形上可能会有相邻共线点 + * 对于连通图,唯一一个面积小于0的面是无限面 +*/ +struct Edge +{ + int u,v; + //double ang; + Edge() {} + Edge(int u,int v):u(u),v(v) {} +}; + +const int MAXN = 10000 + 10; + +//平面直线图 +static double *xp, *yp; +static vector* ep; + +struct PSLG +{ + int n, m, face_cnt; + double x[MAXN], y[MAXN]; + vector edges; + vector G[MAXN]; + int vis[MAXN*2]; //每条边是否已经访问过 + int left[MAXN*2]; //左边的编号 + int prev[MAXN*2]; //相同起点的上一条边(右边的边)的变化 + vector faces; + double area[MAXN]; //每个polygon的面积 + void init(int n) + { + this -> n = n; + for(int i=0; i& V) + { + for(int i=0; i 0) + return (Vector(x1,y1) ^ Vector(x2,y2)) > 0; + if(y1 * y2 < 0) + return y1 < 0; + if(y1 == 0 && y2 == 0) + return x1 > x2; + if(y1 == 0 && x1 > 0) + return y2 > 0; + if(y1 == 0 && x1 <= 0) + return false; + if(x2 > 0) + return y1 < 0; + return true; + } + //找出faces, 并计算面积 + void getFaces() + { + for(int u=0; u edges[G[u][j]].ang) + swap(G[u][i],G[u][j]); + } + }*/ + for(int i=0; iEPS) + return COUNTER_CLOCKWISE; + if(Cross(b,a)>EPS) + return CLOCKWISE; + if(Dot(a,b)<-EPS) + return ONLINE_BACK; + if(Length(a)Length(b)) + return ON_SEGMENT; +} + +//判断两线段是否相交 +bool Intersect(SegMent s1,SegMent s2) +{ + if(CCW(s1.a,s1.b,s2.a)*CCW(s1.a,s1.b,s2.b)<=0 && CCW(s2.a,s2.b,s1.a)*CCW(s2.a,s2.b,s1.b)<=0) + return true; + return false; +} + +//两线段之间的距离 +Type DistanceBetweenTwoSegMent(SegMent s1,SegMent s2) +{ + if(Intersect(s1,s2)) + return 0.0; + return min(min(DistanceToSegMent(s1.a,s2),DistanceToSegMent(s1.b,s2)),min(DistanceToSegMent(s2.a,s1),DistanceToSegMent(s2.b,s1))); +} + +//两线段的交点 +Point CrossPoint(SegMent s1,SegMent s2) +{ + Vector x=s2.b-s2.a; + double d1=fabs(Cross(x,s2.a-s1.a)); + double d2=fabs(Cross(x,s2.b-s1.b)); + double t=d1/(d1+d2); + return s1.a+(s1.b-s1.a)*t; +} + +//点与多边形的关系(内包、在边上、在多边形外) +int Contains(Polygon g, Point p) +{ + int sz=g.v.size(); + bool flag=false; + for(int i=0; ib.y) + swap(a,b); + if(a.yEPS && Cross(a,b)>EPS) + flag=!flag; + } + return flag?2:0; //点在多边形内/点在多边形外 +} diff --git "a/\350\256\241\347\256\227\345\207\240\344\275\225/\350\256\241\347\256\227\345\207\240\344\275\225\346\250\241\346\235\277\347\233\256\345\275\225.txt" "b/\350\256\241\347\256\227\345\207\240\344\275\225/\350\256\241\347\256\227\345\207\240\344\275\225\346\250\241\346\235\277\347\233\256\345\275\225.txt" new file mode 100644 index 0000000..9e986cb --- /dev/null +++ "b/\350\256\241\347\256\227\345\207\240\344\275\225/\350\256\241\347\256\227\345\207\240\344\275\225\346\250\241\346\235\277\347\233\256\345\275\225.txt" @@ -0,0 +1,57 @@ +目录: + +-> A.点、向量、直线与线段相关算法.cpp + #A1.点的定义 + #A2.向量的基本运算 + #A3.直线、线段定义 + #A4.两直线交点 + #A5.点到直线的距离 + #A6.点到线段的距离 + #A7.点在直线上的投影 + #A8.判断点是否在线段上 + #A9.线段相交判定 + #A10.两点式转一般式 Ax + By + C = 0 + #A11.判断直线和线段相交 + #A12.点的极角排序 + #A13.分治法求平面最近点对 + +-> B.圆相关算法.cpp + #B1.圆的定义 + #B2.判断点在圆内 + #B3.直线与圆的交点 + #B4.线段与圆相交判定 + #B5.线段和圆的交点 + #B6.两圆交点 + #B7.两圆面积交 + #B8.把角变成0~2PI范围内 + #B9.求圆过某一点的所有切线 + #B10.求两圆的公切线 + #B11.三角形外接圆 + #B12.三角形内切圆 + #B13.过某一点与直线相切的圆 + #B14.与两条直线相切的圆 + #B15.与两圆相切的圆 + +-> C.多边形和凸包相关算法.cpp + #C1.多边形定义 + #C2.多边形的有向面积 + #C3.点在多边形内判定 + #C4.多边形重心 + #C5.圆和三角形相交的面积(三角形的一个顶点为圆心) + #C6.圆和多边形相交的面积(利用三角剖分) + #C7.返回圆盘是否与多边形相交 + #C8.删除平面的三点共线 + #C9.有向直线切割多边形 + #C10.求点集凸包 + #C11.判断是否是凸包 + #C12.判断圆是否在多边形内 + +-> D.旋转卡壳.cpp + #D1.旋转卡壳求平面最远点对 + #D2.旋转卡壳求两个凸包的最近点对 + #D3.旋转卡壳求平面点集构成的最大三角形面积 + #D4.旋转卡壳求平面点集构成的最大四边形面积 + #D5.旋转卡壳求包围点的最小面积(周长)的矩形 + +-> E.半平面交.cpp + #E1.半平面交 diff --git "a/\351\253\230\347\262\276\345\272\246/C++\345\244\247\346\225\260\347\261\273\357\274\210\351\253\230\347\262\276\345\272\246\345\244\247\346\225\264\346\225\260\345\212\240\345\207\217\344\271\230\351\231\244\345\217\226\346\250\241\357\274\211.cpp" "b/\351\253\230\347\262\276\345\272\246/C++\345\244\247\346\225\260\347\261\273\357\274\210\351\253\230\347\262\276\345\272\246\345\244\247\346\225\264\346\225\260\345\212\240\345\207\217\344\271\230\351\231\244\345\217\226\346\250\241\357\274\211.cpp" new file mode 100644 index 0000000..8495db4 --- /dev/null +++ "b/\351\253\230\347\262\276\345\272\246/C++\345\244\247\346\225\260\347\261\273\357\274\210\351\253\230\347\262\276\345\272\246\345\244\247\346\225\264\346\225\260\345\212\240\345\207\217\344\271\230\351\231\244\345\217\226\346\250\241\357\274\211.cpp" @@ -0,0 +1,710 @@ + +/* C++大数加减乘除取模模板 */ + + +/* 模板一 */ + +struct BigInteger +{ + static const int BASE = 100000000; + static const int WIDTH = 8; + vector s; + + BigInteger& clean() + { + while(!s.back() && s.size() > 1) + s.pop_back(); + return *this; + } + BigInteger(ULL num = 0) + { + *this = num; + } + BigInteger(string s) + { + *this = s; + } + BigInteger& operator = (long long num) + { + s.clear(); + do + { + s.push_back(num % BASE); + num /= BASE; + } + while(num > 0); + return *this; + } + BigInteger& operator = (const string& str) + { + s.clear(); + int x, len = (str.length() - 1) / WIDTH + 1; + for(int i = 0; i < len; i++) + { + int end = str.length() - i * WIDTH; + int start = max(0, end - WIDTH); + sscanf(str.substr(start, end - start).c_str(), "%d", &x); + s.push_back(x); + } + return (*this).clean(); + } + + BigInteger operator + (const BigInteger& b) const + { + BigInteger c; + c.s.clear(); + for(int i = 0, g = 0; ; i++) + { + if(g == 0 && i >= s.size() && i >= b.s.size()) + break; + int x = g; + if(i < s.size()) + x += s[i]; + if(i < b.s.size()) + x += b.s[i]; + c.s.push_back(x % BASE); + g = x / BASE; + } + return c; + } + BigInteger operator - (const BigInteger& b) const + { + assert(b <= *this); // 减数不能大于被减数 + BigInteger c; + c.s.clear(); + for(int i = 0, g = 0; ; i++) + { + if(g == 0 && i >= s.size() && i >= b.s.size()) + break; + int x = s[i] + g; + if(i < b.s.size()) + x -= b.s[i]; + if(x < 0) + { + g = -1; + x += BASE; + } + else + g = 0; + c.s.push_back(x); + } + return c.clean(); + } + BigInteger operator * (const BigInteger& b) const + { + int i, j; + ULL g; + vector v(s.size() + b.s.size(), 0); + BigInteger c; + c.s.clear(); + for(i = 0; i < s.size(); i++) + for(j = 0; j < b.s.size(); j++) + v[i + j] += ULL(s[i]) * b.s[j]; + for(i = 0, g = 0; ; i++) + { + if(g == 0 && i >= v.size()) + break; + ULL x = v[i] + g; + c.s.push_back(x % BASE); + g = x / BASE; + } + return c.clean(); + } + BigInteger operator / (const BigInteger& b) const + { + assert(b > 0); // 除数必须大于0 + BigInteger c = *this; // 商:主要是让c.s和(*this).s的vector一样大 + BigInteger m; // 余数:初始化为0 + for(int i = s.size() - 1; i >= 0; i--) + { + m = m * BASE + s[i]; + c.s[i] = bsearch(b, m); + m -= b * c.s[i]; + } + return c.clean(); + } + BigInteger operator % (const BigInteger& b) const //方法与除法相同 + { + BigInteger c = *this; + BigInteger m; + for(int i = s.size() - 1; i >= 0; i--) + { + m = m * BASE + s[i]; + c.s[i] = bsearch(b, m); + m -= b * c.s[i]; + } + return m; + } + // 二分法找出满足bx<=m的最大的x + int bsearch(const BigInteger& b, const BigInteger& m) const + { + int L = 0, R = BASE - 1, x; + while(1) + { + x = (L + R) >> 1; + if(b * x <= m) + { + if(b * (x + 1) > m) + return x; + else + L = x; + } + else + R = x; + } + } + BigInteger& operator += (const BigInteger& b) + { + *this = *this + b; + return *this; + } + BigInteger& operator -= (const BigInteger& b) + { + *this = *this - b; + return *this; + } + BigInteger& operator *= (const BigInteger& b) + { + *this = *this * b; + return *this; + } + BigInteger& operator /= (const BigInteger& b) + { + *this = *this / b; + return *this; + } + BigInteger& operator %= (const BigInteger& b) + { + *this = *this % b; + return *this; + } + + bool operator < (const BigInteger& b) const + { + if (s.size() != b.s.size()) + return s.size() < b.s.size(); + for (int i = s.size() - 1; i >= 0; i--) + if (s[i] != b.s[i]) + return s[i] < b.s[i]; + return false; + } + bool operator > (const BigInteger& b) const + { + return b < *this; + } + bool operator <= (const BigInteger& b) const + { + return !(b < *this); + } + bool operator >= (const BigInteger& b) const + { + return !(*this < b); + } + bool operator != (const BigInteger& b) const + { + return b < *this || *this < b; + } + bool operator == (const BigInteger& b) const + { + return !(b < *this) && !(b > *this); + } +}; + +ostream& operator << (ostream& out, const BigInteger& x) +{ + out << x.s.back(); + for (int i = x.s.size() - 2; i >= 0; i--) + { + char buf[20]; + sprintf(buf, "%08d", x.s[i]); + for (int j = 0; j < strlen(buf); j++) + out << buf[j]; + } + return out; +} + +istream& operator >> (istream& in, BigInteger& x) +{ + string s; + if (!(in >> s)) + return in; + x = s; + return in; +} + +int main() +{ + int n; + scanf("%d", &n); + BigInteger x = 2; + for(int i = 1; i <= n; i++) + { + cout << x << endl; + x = x * (x - 1) + 1; + } + return 0; +} + + +/* 模板二(能解决更大数的运算且速度更快) */ + +const int DEFAULT_SIZE = 100; +struct BigInteger : vector +{ + static const long long BASE = 100000000; + static const int BASE_DIGIT = 8; + int sign; + + // constructor + BigInteger(long long num = 0) : vector(DEFAULT_SIZE, 0), sign(1) + { + if (num < 0) sign = -1, num = -num; + (*this)[0] = num; + this->normalize(); + } + BigInteger(int size, long long num) : vector(size, num), sign(1) {} + BigInteger& normalize() + { + long long c = 0; + bool exist = false; + for (int i = 0;; ++i) + { + if (i >= this->size()) this->push_back(0); + if ((*this)[i] < 0 && i+1 >= this->size()) this->push_back(0); + while ((*this)[i] < 0) + { + (*this)[i+1] -= 1; + (*this)[i] += BASE; + } + long long a = (*this)[i] + c; + (*this)[i] = a % BASE; + if ((*this)[i]) exist = true; + c = a / BASE; + if (c == 0 && i == this->size()-1) break; + } + if (!exist) sign = 1; + return (*this); + } + friend BigInteger abs(const BigInteger &x) + { + BigInteger z = x; + if (z.sign == -1) z.sign = 1; + return z; + } + friend ostream &operator << (ostream &os, const BigInteger &x) + { + if (x.sign == -1) os << '-'; + int d = x.size()-1; + for (d = x.size()-1; d >= 0; --d) if (x[d] > 0) break; + if (d == -1) os << 0; + else os << x[d]; + for (int i = d-1; i >= 0; --i) + { + os.width(BigInteger::BASE_DIGIT); + os.fill('0'); + os << x[i]; + } + return os; + } + + // operation + BigInteger operator - () const + { + BigInteger res = *this; + bool allzero = true; + for (int i = 0; i < this->size(); ++i) + { + if (res[i] != 0) + { + allzero = false; + break; + } + } + if (!allzero) res.sign = -res.sign; + return res; + } + BigInteger& operator += (const BigInteger& r) + { + while (size() < r.size()) this->emplace_back(0); + if (sign == r.sign) + { + for (int i = 0; i < r.size(); ++i) (*this)[i] += r[i]; + } + else + { + if (sign == 1 && abs(*this) < abs(r)) sign = -1; + else if (sign == -1 && abs(*this) <= abs(r)) sign = 1; + if (abs(*this) >= abs(r)) + { + for (int i = 0; i < r.size(); ++i) (*this)[i] -= r[i]; + } + else + { + for (int i = 0; i < size(); ++i) (*this)[i] = -(*this)[i]; + for (int i = 0; i < r.size(); ++i) (*this)[i] += r[i]; + } + } + return this->normalize(); + } + BigInteger& operator -= (const BigInteger& r) + { + while (size() < r.size()) this->emplace_back(0); + if (sign == -r.sign) + { + for (int i = 0; i < r.size(); ++i) (*this)[i] += r[i]; + } + else + { + if (sign == 1 && abs(*this) < abs(r)) sign = -1; + else if (sign == -1 && abs(*this) <= abs(r)) sign = 1; + if (abs(*this) >= abs(r)) + { + for (int i = 0; i < r.size(); ++i) (*this)[i] -= r[i]; + } + else + { + for (int i = 0; i < size(); ++i) (*this)[i] = -(*this)[i]; + for (int i = 0; i < r.size(); ++i) (*this)[i] += r[i]; + } + } + return this->normalize(); + } + BigInteger& operator *= (long long r) + { + if ( (sign == 1 && r >= 0) || (sign == -1 && r < 0) ) sign = 1; + else sign = -1; + if (r < 0) r = -r; + for (int i = 0; i < size(); ++i) (*this)[i] *= r; + return this->normalize(); + } + BigInteger& operator *= (const BigInteger& r) + { + int tx = (int)size()-1, ty = (int)r.size()-1; + for (tx = size()-1; tx >= 0; --tx) if ((*this)[tx] > 0) break; + for (ty = r.size()-1; ty >= 0; --ty) if (r[ty] > 0) break; + BigInteger res(0); + res.resize(tx+ty+2); + if (sign == r.sign) res.sign = 1; + else res.sign = -1; + for (int i = 0; i <= tx; ++i) + { + for (int j = 0; j <= ty && i+j < (int)res.size()-1; ++j) + { + long long val = (*this)[i] * r[j] + res[i+j]; + res[i+j+1] += val / BigInteger::BASE; + res[i+j] = val % BigInteger::BASE; + } + } + return (*this) = res.normalize(); + } + friend BigInteger pow(const BigInteger& a, long long n) + { + BigInteger res(1), b = a; + while (n > 0) + { + if (n & 1) res = res * b; + b = b * b; + n >>= 1; + } + return res; + } + BigInteger operator + (const BigInteger& r) const + { + return BigInteger(*this) += r; + } + BigInteger operator - (const BigInteger& r) const + { + return BigInteger(*this) -= r; + } + BigInteger operator * (long long r) const + { + return BigInteger(*this) *= r; + } + BigInteger operator * (const BigInteger& r) const + { + return BigInteger(*this) *= r; + } + + // divide + BigInteger& operator /= (long long r) + { + if (r < 0) sign *= -1, r = -r; + long long c = 0, t = 0; + for (int i = (int)size()-1; i >= 0; --i) + { + t = BigInteger::BASE * c + (*this)[i]; + (*this)[i] = t / r; + c = t % r; + } + this -> normalize(); + return (*this); + } + long long operator %= (long long r) + { + if(r < 0) + sign *= -1, r = -r; + long long c = 0, t = 0; + for(int i = (int)size() - 1; i >= 0; --i) + { + t = BigInteger :: BASE * c + (*this)[i]; + (*this)[i] = t / r; + c = t % r; + } + return c; + } + BigInteger operator / (long long r) const + { + return BigInteger(*this) /= r; + } + long long operator % (long long r) const + { + return BigInteger(*this) %= r; + } + friend pair divmod(const BigInteger &a, const BigInteger &r) + { + BigInteger zero = 0, s = 0, t = 0; + if (abs(a) < abs(r)) return {zero, a}; + BigInteger ar = abs(r); + s.resize((int)a.size()), t.resize((int)r.size()); + int tx = (int)a.size()-1; + for (; tx >= 0; --tx) if (a[tx] > 0) break; + for (int i = tx; i >= 0; --i) + { + t = t * BigInteger :: BASE + a[i]; + long long lo = 0, hi = BigInteger::BASE; + if(t >= ar) + { + while(hi - lo > 1) + { + int mid = (hi + lo) / 2; + if(ar * mid > t) + hi = mid; + else + lo = mid; + } + t -= ar * lo; + } + s[i] = lo; + } + if(a.sign == r.sign) + s.sign = 1, t.sign = 1; + else + s.sign = -1, t.sign = 1; + return make_pair(s.normalize(), t.normalize()); + } + BigInteger operator / (const BigInteger& r) const + { + return divmod((*this), r).first; + } + BigInteger operator % (const BigInteger& r) const + { + return divmod((*this), r).second; + } + BigInteger& operator /= (const BigInteger& r) + { + return (*this) = (*this) / r; + } + BigInteger& operator %= (const BigInteger& r) + { + return (*this) = (*this) % r; + } + + // equality + friend bool operator < (const BigInteger &x, const BigInteger& y) + { + if(x.sign < y.sign) + return true; + else if(x.sign > y.sign) + return false; + else + { + int tx = (int)x.size() - 1, ty = (int)y.size() - 1; + for(tx = x.size() - 1; tx >= 0; --tx) + { + if(x[tx] > 0) + break; + } + for(ty = y.size() - 1; ty >= 0; --ty) + { + if(y[ty] > 0) + break; + } + if(tx < ty) + return true; + else if(tx > ty) + return false; + else if(x.sign == 1) + { + for(int i = tx; i >= 0; --i) + { + if(x[i] != y[i]) + return x[i] < y[i]; + } + return false; + } + else + { + for(int i = tx; i >= 0; --i) + { + if(x[i] != y[i]) + return x[i] > y[i]; + } + return false; + } + } + } + friend bool operator > (const BigInteger& x, const BigInteger& y) + { + return y < x; + } + friend bool operator <= (const BigInteger& x, const BigInteger& y) + { + return !(x > y); + } + friend bool operator >= (const BigInteger& x, const BigInteger& y) + { + return !(x < y); + } + friend bool operator == (const BigInteger &x, const BigInteger& y) + { + if(x.sign != y.sign) + return false; + int tx = (int)x.size() - 1, ty = (int)y.size() - 1; + for(tx = x.size() - 1; tx >= 0; --tx) + { + if (x[tx] > 0) + break; + } + for(ty = y.size() - 1; ty >= 0; --ty) + { + if(y[ty] > 0) + break; + } + if(tx != ty) + return false; + for(int i = tx; i >= 0; --i) + { + if(x[i] != y[i]) + return false; + } + return true; + } + friend bool operator != (const BigInteger& x, const BigInteger& y) + { + return !(x == y); + } +}; + +BigInteger toBigInteger(const string &is) +{ + string s = is; + if(s[0] == '-') + s = s.substr(1); + while(s.size() % 8 != 0) + s = "0" + s; + int N = (int)s.size(); + BigInteger res(N / 8, 0); + for(int i = 0; i < (int)s.size(); ++i) + { + res[(N - i - 1) / 8] *= 10; + res[(N - i - 1) / 8] += s[i] - '0'; + } + if(is[0] == '-') + res.sign = -1; + return res; +} + +string toStr(const BigInteger &r) +{ + stringstream ss; + if(r.sign == -1) + ss << '-'; + int d = (int)r.size() - 1; + for(; d >= 0; --d) + { + if(r[d] > 0) + break; + } + if(d == -1) + ss << 0; + else + ss << r[d]; + for(int i = d - 1; i >= 0; --i) + { + ss.width(BigInteger::BASE_DIGIT); + ss.fill('0'); + ss << r[i]; + } + return ss.str(); +} + +int main() +{ + string A, B; + cin >> A >> B; + cout << toBigInteger(A) + toBigInteger(B) << endl; + //cout << toBigInteger(A) - toBigInteger(B) << endl; + //cout << toBigInteger(A) * toBigInteger(B) << endl; + //cout << toBigInteger(A) / toBigInteger(B) << endl; + //cout << toBigInteger(A) % toBigInteger(B) << endl; +} + + +/* 模板三:快速傅里叶变换(FFT)求大数乘法 */ + +/* 需要数学分类中的FFT模板 */ +void FFT_Mul(char *s1, char *s2) //传入的是两个相乘的大数 +{ + int len1 = strlen(s1), len2 = strlen(s2); + reverse(s1, s1 + len1); + reverse(s2, s2 + len2); + int sign = 0; //符号 + if(s1[len1 - 1] == '-') + { + len1--; + sign ^= 1; + } + if(s2[len2 - 1] == '-') + { + len2--; + sign ^= 1; + } + for(int i = 0; i < len1; i++) + a[i] = (double)(s1[i] - '0'); + for(int i = 0; i < len2; i++) + b[i] = (double)(s2[i] - '0'); + int len = 1; + while(len < len1 + len2 - 1) + len <<= 1; + solve(len); + for(int i = 0; i < len; i++) + { + ans[i] += (int)(a[i].real() + 0.5); + ans[i + 1] += ans[i] / 10; + ans[i] %= 10; + } + while(len >= 0 && !ans[len]) + len--; + if(len == -1) + puts("0"); + else + { + if(sign) + printf("-"); + for(int i = len; i >= 0; i--) + { + if(i == len && !ans[len]) + continue; + printf("%d", ans[i]); + } + puts(""); + } +} + +int main() +{ + scanf("%s%s", s1, s2); + FFT_Mul(s1, s2); + return 0; +} + diff --git "a/\351\253\230\347\262\276\345\272\246/Java\351\253\230\347\262\276\345\272\246\344\270\216\345\255\227\347\254\246\344\270\262.java" "b/\351\253\230\347\262\276\345\272\246/Java\351\253\230\347\262\276\345\272\246\344\270\216\345\255\227\347\254\246\344\270\262.java" new file mode 100644 index 0000000..01ef902 --- /dev/null +++ "b/\351\253\230\347\262\276\345\272\246/Java\351\253\230\347\262\276\345\272\246\344\270\216\345\255\227\347\254\246\344\270\262.java" @@ -0,0 +1,209 @@ +/*输入*/ +Scanner in = new Scanner (System.in); +Scanner in = new Scanner (new BufferedInputStream(System.in)); + + +/*输入挂*/ +class InputReader { + BufferedReader buf; + StringTokenizer tok; + InputReader() { + buf = new BufferedReader(new InputStreamReader(System.in)); + } + boolean hasNext() { + while (tok == null || !tok.hasMoreElements()) { + try { + tok = new StringTokenizer(buf.readLine()); + } catch (Exception e) { + return false; + } + } + return true; + } + String next() { + if (hasNext()) + return tok.nextToken(); + return null; + } + int nextInt() { + return Integer.parseInt(next()); + } + long nextLong() { + return Long.parseLong(next()); + } + double nextDouble() { + return Double.parseDouble(next()); + } + BigInteger nextBigInteger() { + return new BigInteger(next()); + } + BigDecimal nextBigDecimal() { + return new BigDecimal(next()); + } +} + + +/*输出*/ +System.out.println(x); +PrintWriter out = new PrintWriter(new BufferedOutputStream(System.out)); +out.println(n); +out.printf("%.2f\n", ans); //与c语言中printf用法相同 + + +/*输入输出示例*/ +import java.io.*; +import java.util.*; +import java.math.*; + +public class Main { + public static void main(String[] args) { + Scanner cin = new Scanner (new BufferedInputStream(System.in)); + /*while(cin.hasNext()) { + ... + } + */ + int n; + n = cin.nextInt(); + BigInteger x = BigInteger.valueOf(2); + BigInteger[] a = new BigInteger[105]; + BigInteger[][] dp = new BigInteger[105][1005]; + /*if(x.equals(BigInteger.ZERO)) { + ... + } + */ + for(int i = 1; i <= n; i++) { + System.out.println(x); + x = x.multiply(x.subtract(BigInteger.valueOf(1))).add(BigInteger.valueOf(1)); + } + cin.close(); + } +} + + + +/*BigInteger*/ +import java.math.BigInteger; +//常量定义: +static BigInteger ONE //大整数 1 +static BigInteger TEN //大整数 10 +static BigInteger ZERO //大整数 0 +//主要有以下方法可以使用: +BigInteger abs() //绝对值(abs(this)) +BigInteger add(BigInteger val) //加法(this + val) +BigInteger subtract(BigInteger val) //减法(this - val) +BigInteger multiply(BigInteger val) //乘法(this * val) +BigInteger divide(BigInteger val) //除法(this / val) +BigInteger [] dividedandRemainder(BigInteger val) //余数和商(返回一个数组:第一位是商,第二位是余数) +BigInteger pow(int val) //val次幂(this ** val) +BigInteger mod(BigInteger val) //对val取模(this % val) +BigInteger gcd(BigInteger val) //最大公约数(gcd(this, val)) +BigInteger and(BigInteger val) //取与(this & val) +BigInteger andNot(BigInteger val) //与反(this & ~val) +BigInteger not() //取反(~this) +BigInteger or(BigInteger val) //取或(this | val) +BigInteger xor(BigInteger val) //取或(this ^ val) +BigInteger shiftLeft(int n) //左移(this << n) +BigInteger shiftRight(int n) //右移(this >> n) +BigInteger max(BigInteger val) //取最大值(max(this, val)) +BigInteger min(BigInteger val) //取最小值(min(this, val)) +BigInteger modInverse(BigInteger m) //求逆元(this ** (-1) % m) +BigInteger modPow(BigInteger exponent, BigInteger m) //求模幂(this ** exponent % m) +static BigInteger valueOf(long val) //把长整数val转化为大整数值 +int compareTo(BigInteger val) //相当于 x 与 val 比较(this CMP val) +boolean equals(Object x) //判断是否相等(this == x) +int intValue() //转换为整形变量 +long longValue() //转换为长整形变量 +String toString() //转换为字符串 +//输出数字时直接使用 System.out.println(a) 即可 + + +/*BigDecimal*/ +import java.math.BigDecimal; +//常量定义: +static BigDecimal ONE //高精度小数 1(不保留小数点后的0) +static BigDecimal TEN //高精度小数 10(不保留小数点后的0) +static BigDecimal ZERO //高精度小数 0(不保留小数点后的0) +//主要有以下方法可以使用: +BigDecimal abs() //绝对值(abs(this)) +BigDecimal add(BigDecimal val) //加法(this + val) +BigDecimal subtract(BigDecimal val) //减法(this - val) +BigDecimal multiply(BigDecimal val) //乘法(this * val) +BigDecimal divide(BigDecimal val) //除法(this / val) +BigDecimal divide(BigDecimal divisor, int scale, BigDecimal.ROUND_HALF_UP) +BigDecimal pow(int k) //k次幂(this ** k) +BigDecimal stripTrailingZeros() //将小数点后多余的零去掉(例如 1.00 -> 1) +BigDecimal setScale() //用于格式化小数点:setScale(1)表示保留一位小数,默认用四舍五入方式 +static BigDecimal valueOf(double val) //把浮点数val转换为高精度小数 +static BigDecimal valueOf(long val) //把长整数val转换为高精度小数 +boolean equals(Object x) //判断是否相等(this == x) +int intValue() //转换为整形变量 +long longValue() //转换为长整形变量 +float floatValue() //转换为单精度浮点数 +double doubleValue() //转换为双精度浮点数 +String toPlainString() //直接原样转换为字符串格式 +String toString() //转换为用科学计数法表示的字符串格式 +//输出数字时直接使用 System.out.println(a) 即可 + + +/*字符串*/ +String st = "abcdefg"; +char [] ch; +ch = st.toCharArray(); //字符串转换为字符数组. +for(int i = 0; i < ch.length; i++) { + ch[i] += 1; //字符数组可以像C++一样操作 +} +System.out.println(ch); //输入为“bcdefgh”. + +boolean startsWith(String str) //判断字符串的前缀是否为str +String substring(int beginIndex, int endIndex) //截取字符串的子串(beginIndex为子串起始下标,endIndex为子串的结束下标) + + +/*进制转换*/ +String s = Integer.toString(a, x); //把int型数据转换乘X进制数并转换成string型 +//0123456789abcdefghijklmnopqrstuvwxyz, 2<=x<=36 +int b = Integer.parseInt(s, x); //把字符串当作X进制数转换成int型 + + +/*控制台输入输出重定向到文件*/ +FileInputStream fis = new FileInputStream("b.in"); +System.setIn(fis); +PrintStream ps = new PrintStream(new FileOutputStream("b.out")); +System.setOut(ps); + + +/*Array.sort()*/ +//1、Arrays.sort(int[] a, int fromIndex, int toIndex) +//这种形式是对数组部分排序,也就是对数组a的下标从fromIndex到toIndex-1的元素排序, +//注意:下标为toIndex的元素不参与排序哦! +//2、public static void sort(T[] a,int fromIndex, int toIndex, Comparator c) +public class Main { + public static void main(String[] args) { + //注意,要想改变默认的排列顺序,不能使用基本类型(int,double, char) + //而要使用它们对应的类 + Integer[] a = {9, 8, 7, 2, 3, 4, 1, 0, 6, 5}; + //定义一个自定义类MyComparator的对象 + Comparator cmp = new MyComparator(); + Arrays.sort(a, cmp); + for(int i = 0; i < a.length; i ++) { + System.out.print(a[i] + " "); + } + } +} +//Comparator是一个接口,所以这里我们自己定义的类MyComparator要implents该接口 +//而不是extends Comparator +class MyComparator implements Comparator{ + @Override + public int compare(Integer o1, Integer o2) { + //如果n1小于n2,我们就返回正值,如果n1大于n2我们就返回负值, + //这样颠倒一下,就可以实现反向排序了 + if(o1 < o2) { + return 1; + }else if(o1 > o2) { + return -1; + }else { + return 0; + } + } +} +//3、lambda(仅 JAVA8 支持) +//Arrays.sort(Point[] p, int fromIndex, int toIndex, (a,b)->(a.x!=b.x?a.x-b.x:a.y-b.y)) \ No newline at end of file