Loading docs/dp/index.md +6 −3 Original line number Diff line number Diff line Loading @@ -97,10 +97,13 @@ ```cpp int a[MAXN]; int dp() { int now = 0, ans = 1; int now = 1, ans = 1; for (int i = 2; i <= n; i++) { if (a[i] > a[i - 1]) ans++; now = max(now, ans); if (a[i] > a[i - 1]) now++; else now = 1; ans = max(now, ans); } return ans; } Loading docs/graph/2-sat.md +1 −1 Original line number Diff line number Diff line > SAT 是适定性(Satisfiability)问题的简称。一般形式为 k - 适定性问题,简称 k-SAT。而当 $k>2$ 时该问题为 NP 完全的。所以我们之研究 $k=2$ 的情况。 > SAT 是适定性(Satisfiability)问题的简称。一般形式为 k - 适定性问题,简称 k-SAT。而当 $k>2$ 时该问题为 NP 完全的。所以我们只研究 $k=2$ 的情况。 ## 定义 Loading docs/graph/index.md +8 −8 Original line number Diff line number Diff line Loading @@ -40,23 +40,23 @@ ## 结点的度数 设图 $G= \langle V,E\rangle$ 为一个有向图, $v\in V$ ,关联于结点 $v$ 的 **边** 的条数,称为点 $v$ 的度数,记作 $deg(v)$ 。 设图 $G= \langle V,E\rangle$ 为一个有向图, $v\in V$ ,关联于结点 $v$ 的 **边** 的条数,称为点 $v$ 的度数,记作 $\deg(v)$ 。 注意:一个自环为它的端点增加 2 度。 当图 $G= \langle V,E\rangle$ 为一个有向图, $v\in V$ ,称以 $v$ 作为始点的边数之和称为结点 $v$ 的出度,记为 $deg^{+} (v)$ 。将以 $v$ 作为终点的边数之和称为结点 $v$ 的入度,记为 $deg^{-} (v)$ 。称以 $v$ 作为端点的边数之和为结点 $v$ 的度数或度,记为 $deg(v)$ 。 当图 $G= \langle V,E\rangle$ 为一个有向图, $v\in V$ ,称以 $v$ 作为始点的边数之和称为结点 $v$ 的出度,记为 $\deg^{+} (v)$ 。将以 $v$ 作为终点的边数之和称为结点 $v$ 的入度,记为 $\deg^{-} (v)$ 。称以 $v$ 作为端点的边数之和为结点 $v$ 的度数或度,记为 $\deg(v)$ 。 显然, $\forall v\in V,deg(v)=deg^{+} (v)+deg^{-} (v)$ 。 显然, $\forall v\in V,\deg(v)=deg^{+} (v)+\deg^{-} (v)$ 。 ### 定理 1 $\sum_{v\in V} deg(v)=2\times |E|$ $\sum_{v\in V} \deg(v)=2\times |E|$ 推论:在任意图中,度数为奇数的点必然有偶数个。 ### 定理 2 $\sum_{v\in V} deg^{+} (v)=\sum_{v\in V} deg^{-} (v)=|E|$ $\sum_{v\in V} \deg^{+} (v)=\sum_{v\in V} \deg^{-} (v)=|E|$ 即所有点入度之和等于出度之和。 Loading @@ -78,19 +78,19 @@ 树:边数比结点数少一的连通图。更多内容,详见[树相关基础](/graph/tree-basic/)。 森林:由 $m$ 棵( $m\ge 0$ )互不相交的树组成的图。 森林:由 $m$ 棵( $m\ge 0$ )互不相交的树组成的图。 基环树:边数和点数相等的连通图。 仙人掌:每个结点至多在一个简单环上的图。 在无向图中,关联一对顶点的边多于 1 条,则称这些边为重边(平行边),重边的条数称为重数。 在无向图中,关联一对顶点的边多于 $1$ 条,则称这些边为重边(平行边),重边的条数称为重数。 简单图:不含重边和自环的图。 多重图:含重边的图。 完全图:每对不同的顶点之间都恰连有一条边相连的简单无向图。容易证明, $n$ 个顶点的完全图有 $\frac{n\times (n-1)}{2}$ 条边。 完全图:每对不同的顶点之间都恰连有一条边相连的简单无向图。容易证明, $n$ 个顶点的完全图有 $\dfrac{n(n-1)}{2}$ 条边。 竞赛图:通过在完全图中为每条边分配方向而获得的有向图。 Loading docs/math/du-sieves.md +5 −5 Original line number Diff line number Diff line Loading @@ -67,12 +67,12 @@ $$ 那么假如我们可以快速对 $\sum_{i=1}^n(f\times g)(i)$ 求和,并用数论分块求解 $\sum_{i=2}^ng(i)S\left(\left\lfloor\frac{n}{i}\right\rfloor\right)$ 就可以在较短时间内求得 $g(1)S(n)$. ## 【例 1】模板 ## 问题一 ??? note " [P4213【模板】杜教筛(Sum)](https://www.luogu.org/problemnew/show/P4213)" 题目大意:求 $S_1(n)= \sum_{i=1}^{n} \mu(i)$ 和 $S_2(n)= \sum_{i=1}^{n} \varphi(i)$ 的值, $n\le 2^{31} -1$ 。 ### 求解 $\mu$ 前缀和 ### 莫比乌斯函数前缀和 由 **狄利克雷卷积** ,我们知道: Loading @@ -92,7 +92,7 @@ $$ 对于较大的值,需要用 `map` 存下其对应的值,方便以后使用时直接使用之前计算的结果。 ### 求解 $\varphi$ 前缀和 ### 欧拉函数前缀和 当然也可以用杜教筛求出 $\varphi (x)$ 的前缀和,但是更好的方法是应用莫比乌斯反演: Loading @@ -104,7 +104,7 @@ $$ 观察到,只需求出莫比乌斯函数的前缀和,就可以快速计算出欧拉函数的前缀和了。时间复杂度 $O(n^{\frac 2 3})$ 。 ### 使用杜教筛求解 $\varphi$ 前缀和 #### 使用杜教筛求解 求 $S(i)=\sum_{i=1}^n\varphi(i)$. Loading Loading @@ -177,7 +177,7 @@ int main() { } ``` ## 【例 2】简单的数学题 ## 问题二 ??? note " [[LuoguP3768] 简单的数学题](https://www.luogu.org/problemnew/show/P3768)" 大意:求 Loading docs/math/simplex.md +168 −185 Original line number Diff line number Diff line Loading @@ -40,7 +40,7 @@ $$ $$ s.t \begin{cases} \sum_{j = 1}^{n}a_{ij}x_j = b_j, i = 1,2,...,m\\ \displaystyle \sum_{j = 1}^{n}a_{ij}x_j = b_j, i = 1,2,...,m\\ xj \geq 0 , j = 1,2,...,n \\ \end{cases} $$ Loading Loading @@ -71,7 +71,7 @@ $$ 标准形的形式为: - 1)目标函数要求max - 1)目标函数要求 $\max$ - 2)约束条件均为等式 Loading Loading @@ -136,7 +136,7 @@ $$ 还是通过上述具体的线性规划问题来说明: $$ max \ z = x_1 + x_2 \max \ z = x_1 + x_2 $$ $$ Loading @@ -147,7 +147,7 @@ x_1, x_2, x_3, x_4 \geq 0 \end{cases} $$ 如果选择 $x_2$ 、$x_3$ 为基变量,那么令 $x_1$、$x_4$ 等于 $0$ ,可以去求解基变量 $x_2$ 、$x_3$ 的值。对系数矩阵做行变换,如下所示,$x_2=9/2$ ,$x_3=15/2$。 如果选择 $x_2$ 、$x_3$ 为基变量,那么令 $x_1$、$x_4$ 等于 $0$ ,可以去求解基变量 $x_2$ 、$x_3$ 的值。对系数矩阵做行变换,如下所示,$x_2=9/2$ ,$x_3=15/2$。 $$ \left[\begin{array}{ccccc}{\mathrm{X}} & {x_{1}} & {x_{2}} & {x_{3}} & {x_{4}} & {b} \\ {} & {2} & {1} & {1} & {0} & {12} \\ {} & {1} & {2} & {0} & {1} & {9} \\ {\mathrm{C}} & {1} & {1} & {0} & {0} & {z}\end{array}\right] \rightarrow\left[\begin{array}{ccccc}{\mathrm{X}} & {x_{1}} & {x_{2}} & {x_{3}} & {x_{4}} & {b} \\ {} & {\frac{3}{2}} & {0} & {1} & {-\frac{1}{2}} & {\frac{15}{2}} \\ {} & {\frac{1}{2}} & {1} & {0} & {\frac{1}{2}} & {\frac{9}{2}} \\ {\mathrm{C}} & {\frac{1}{2}} & {0} & {0} & {-\frac{1}{2}} & {z-\frac{9}{2}}\end{array}\right] Loading Loading @@ -293,37 +293,30 @@ double Z; set<int> P; size_t cn, bn; bool Pivot(pair<size_t, size_t> &p)//返回0表示所有的非轴元素都小于0 { bool Pivot(pair<size_t, size_t> &p) { //返回0表示所有的非轴元素都小于0 int x = 0, y = 0; double cmax = -INT_MAX; vector<double> C = Matrix[0]; vector<double> B; for( size_t i = 0 ; i < bn ; i++ ) { for(size_t i = 0 ; i < bn ; i++) { B.push_back(Matrix[i][cn - 1]); } for( size_t i = 0 ; i < C.size(); i++ )//在非轴元素中找最大的c { if( cmax < C[i] && P.find(i) == P.end()) { for(size_t i = 0 ; i < C.size(); i++) { //在非轴元素中找最大的c if(cmax < C[i] && P.find(i) == P.end()) { cmax = C[i]; y = i; } } if( cmax < 0 ) { if(cmax < 0) { return 0; } double bmin = INT_MAX; for( size_t i = 1 ; i < bn ; i++ ) { for(size_t i = 1 ; i < bn ; i++) { double tmp = B[i] / Matrix[i][y]; if( Matrix[i][y] != 0 && bmin > tmp ) { if(Matrix[i][y] != 0 && bmin > tmp) { bmin = tmp; x = i; } Loading @@ -331,10 +324,8 @@ bool Pivot(pair<size_t, size_t> &p)//返回0表示所有的非轴元素都小于 p = make_pair(x, y); for( set<int>::iterator it = P.begin() ; it != P.end() ; it++) { if( Matrix[x][*it] != 0 ) { for(set<int>::iterator it = P.begin() ; it != P.end() ; it++) { if(Matrix[x][*it] != 0) { //cout<<"erase "<<*it<<endl; P.erase(*it); break; Loading @@ -345,12 +336,9 @@ bool Pivot(pair<size_t, size_t> &p)//返回0表示所有的非轴元素都小于 return true; } void pnt() { for( size_t i = 0 ; i < Matrix.size() ; i++ ) { for( size_t j = 0 ; j < Matrix[0].size() ; j++ ) { void pnt() { for(size_t i = 0 ; i < Matrix.size() ; i++) { for(size_t j = 0 ; j < Matrix[0].size() ; j++) { cout << Matrix[i][j] << "\t"; } cout << endl; Loading @@ -358,42 +346,33 @@ void pnt() cout << "result z:" << -Matrix[0][cn - 1] << endl; } void Gaussian(pair<size_t, size_t> p)//行变换 { void Gaussian(pair<size_t, size_t> p) { //行变换 size_t x = p.first; size_t y = p.second; double norm = Matrix[x][y]; for( size_t i = 0 ; i < cn ; i++ )//主行归一化 { for(size_t i = 0 ; i < cn ; i++) { //主行归一化 Matrix[x][i] /= norm; } for( size_t i = 0 ; i < bn && i != x; i++ ) { if( Matrix[i][y] != 0) { for(size_t i = 0 ; i < bn && i != x; i++) { if(Matrix[i][y] != 0) { double tmpnorm = Matrix[i][y]; for( size_t j = 0 ; j < cn ; j++ ) { for(size_t j = 0 ; j < cn ; j++) { Matrix[i][j] = Matrix[i][j] - tmpnorm * Matrix[x][j]; } } } } void solve() { void solve() { pair<size_t, size_t> t; while(1) { while(1) { pnt(); if( Pivot(t) == 0 ) { if(Pivot(t) == 0) { return; } cout << t.first << " " << t.second << endl; for( set<int>::iterator it = P.begin(); it != P.end() ; it++ ) { for(set<int>::iterator it = P.begin(); it != P.end() ; it++) { cout << *it << " "; } cout << endl; Loading @@ -401,16 +380,13 @@ void solve() } } int main(int argc, char *argv[]) { int main(int argc, char *argv[]) { //ifstream fin; //fin.open("./test"); cin >> cn >> bn; for( size_t i = 0 ; i < bn ; i++ ) { for(size_t i = 0 ; i < bn ; i++) { vector<double> vectmp; for( size_t j = 0 ; j < cn ; j++) { for(size_t j = 0 ; j < cn ; j++) { double tmp = 0; cin >> tmp; vectmp.push_back(tmp); Loading @@ -418,8 +394,7 @@ int main(int argc, char *argv[]) Matrix.push_back(vectmp); } for( size_t i = 0 ; i < bn-1 ; i++ ) { for(size_t i = 0 ; i < bn - 1 ; i++) { P.insert(cn - i - 2); } solve(); Loading Loading @@ -459,7 +434,7 @@ int main(int argc, char *argv[]) ### 6.1 标准型 $m+n$ 个约束 $n$ 个变量用 $x$ 向量表示,$A$ 是一个 $m*n$ 的矩阵,$c$ 是一个 $n$ 的向量,$b$ 是一个 $m$ 的向量,最大化 $cx$ 满足约束 $Ax \leq b,x > 0$。 $m+n$ 个约束 $n$ 个变量用 $x$ 向量表示,$A$ 是一个 $m\times n$ 的矩阵,$c$ 是一个 $n$ 的向量,$b$ 是一个 $m$ 的向量,最大化 $cx$ 满足约束 $Ax \leq b,x > 0$。 最大化 $\sum_{j=1}^nc_jx_j$ 满足如下约束条件: $$ Loading @@ -484,7 +459,7 @@ $$ ### 6.2 转换为标准型 若目标函数要求取最小值,那么可以对其取相反数变成取最大值。对于限制条件 $f(x_1, x_2, \ldots ,x_n) = b$,可以用两个不等式 $f(x_1, x2, \ldots, x_n) \leq b,-f(x_1,x_2,\ldots,x_n) \leq -b$ 描述,对于限制条件 $f(x_1,x_2,\ldots,x_n) \geq b$,可以用不等式 $-f(x_1,x_2,\ldots,x_n) \leq -b$ 描述。对于无限制的变量 $x$,可以将其拆为两个非负变量 $x_0,x_1$,使得 $x = x_0 - x_1$。 若目标函数要求取最小值,那么可以对其取相反数变成取最大值。对于限制条件 $f(x_1, x_2, \ldots ,x_n) = b$,可以用两个不等式 $f(x_1, x_2, \ldots, x_n) \leq b,-f(x_1,x_2,\ldots,x_n) \leq -b$ 描述,对于限制条件 $f(x_1,x_2,\ldots,x_n) \geq b$,可以用不等式 $-f(x_1,x_2,\ldots,x_n) \leq -b$ 描述。对于无限制的变量 $x$,可以将其拆为两个非负变量 $x_0,x_1$,使得 $x = x_0 - x_1$。 ### 6.3 松弛型 Loading @@ -505,15 +480,15 @@ $$ ### 6.5 可行解 - 基本解:所有非基变量设为0,基本变量为右侧的常数 - 基本解:所有非基变量设为 $0$,基本变量为右侧的常数 - 基本可行解:所有 $b_i \geq 0$ - 基本可行解:所有 $b_i \geq 0$ > 注:单纯形法的过程中B和N不断交换,在n维空间中不断走,“相当于不等式上的高斯消元”。 ### 6.6 转轴 选取一个非基本变量 $x_e$ 为替入变量,基本变量 $x_l$ 为替出变量,将其互换,为了防止循环,根据 **Bland规则** ,选择下标最小的变量。 选取一个非基本变量 $x_e$ 为替入变量,基本变量 $x_l$ 为替出变量,将其互换,为了防止循环,根据 **Bland规则** ,选择下标最小的变量。 > **Bland规则** 可以参看:[最优化方法](https://github.com/AngelKitty/review_the_national_post-graduate_entrance_examination/blob/master/books_and_notes/professional_courses/data_structures_and_algorithms/sources/extra_books/%E6%9C%80%E4%BC%98%E5%8C%96%E6%96%B9%E6%B3%95.pdf) Loading @@ -534,24 +509,24 @@ $$ 基本思想就是改写 $l$ 这个约束为 $x_e$ 作为基本变量,然后把这个新 $x_e$ 的值带到其他约束和目标函数中,就消去 $x_e$ 了。改写和带入时要修改 $b$ 和 $a$,目标函数则是 $c$ 和 $v$。 转动时,$l$ 和 $e$ 并没有像算法导论上一样,$a$ 矩阵用了两行分别是 $a[l][ \ ]$和 $a[e][ \ ]$(这样占用内存大),而是用了同一行,这样 $a$ 矩阵的行数 $=|B|$,列数 $=|N|$。 转动时,$l$ 和 $e$ 并没有像算法导论上一样,$a$ 矩阵用了两行分别是 $a_{l, \square}$ 和 $a_{e, \square}$(这样占用内存大),而是用了同一行,这样 $a$ 矩阵的行数 $=|B|$,列数 $=|N|$。 也就是说,约束条件只用 $m$ 个,尽管 $B$ 和 $N$ 不断交换,但同一时间还是只有 $m$ 个约束(基本变量),$n$ 个非基变量,注意改写成松弛型后 $a$ 矩阵实际系数为负。(一个优化 $a[i][e]$为 $0$ 的约束没必要带入了。 也就是说,约束条件只用 $m$ 个,尽管 $B$ 和 $N$ 不断交换,但同一时间还是只有 $m$ 个约束(基本变量),$n$ 个非基变量,注意改写成松弛型后 $a$ 矩阵实际系数为负。(一个优化为 $a_{i,e}$ 的约束没必要带入了。 `simplex` 是主过程,基本思想是找到一个 $c[e]>0$ 的,然后找对这个 $e$ 限制最紧的 $l$ ,转动这组 $l,e$,注意精度控制 $eps$,$c[e]>eps$, 还有找 $l$ 的时候 $a[i][e]>eps$ 才行。 `simplex` 是主过程,基本思想是找到一个 $c_e>0$ 的,然后找对这个 $e$ 限制最紧的 $l$ ,转动这组 $l,e$,注意精度控制 $\epsilon$,$c_e>\epsilon$, 还有找 $l$ 的时候 $a_{i,e}>\epsilon$ 才行。 ??? note " 例题 [BZOJ1061 志愿者招募](https://www.lydsy.com/JudgeOnline/problem.php?id=1061)" 题目大意:长度为 $n$ 的序列,第 $i$ 位至少 $b_i$,$m$ 种区间使 $[l_i,r_i] + 1$ 代价为 $a_i$。 题目大意:长度为 $n$ 的序列,第 $i$ 位至少 $b_i$,$m$ 种区间使 $[l_i,r_i] + 1$ 代价为 $a_i$。 原始问题 $m$ 个变量,$n$ 个约束,当 $l_j \leq i \leq r_j$,$a_{ij} = 1$。 原始问题 $m$ 个变量,$n$ 个约束,当 $l_j \leq i \leq r_j$,$a_{ij} = 1$。 对偶问题 $n$ 个变量,$m$ 个约束 对偶问题 $n$ 个变量,$m$ 个约束 $$ \max \ \sum_{i=1}nb_iy_i $$ $$ Sat \ \sum_{l_i \leq j \leq r_i}y_j \leq c_i, y_i \geq 0 s.t \ \sum_{l_i \leq j \leq r_i}y_j \leq c_i, y_i \geq 0 $$ 把对应出的系数矩阵带入到单纯形算法就可以求出最优解了。 Loading @@ -567,9 +542,16 @@ typedef long long ll; const int M = 10005, N = 1005, INF = 1e9; const double eps = 1e-6; inline int read() { char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();} char c = getchar(); int x = 0, f = 1; while(c < '0' || c > '9') { if(c == '-')f = -1; c = getchar(); } while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); } return x * f; } Loading Loading @@ -607,7 +589,8 @@ double simplex(){ } int main() { n=read();m=read(); n = read(); m = read(); for(int i = 1; i <= n; i++) c[i] = read(); for(int i = 1; i <= m; i++) { int s = read(), t = read(); Loading Loading @@ -636,7 +619,7 @@ $$ $$ $$ Sat \begin{cases} s.t \begin{cases} \sum_{(v) \in Y} d_{uv} \leq 1, u \in X \\ \sum_{(u) \in X} d_{uv} \leq 1, v \in Y \\ d_{u,v} \in \{0,1\} Loading @@ -649,7 +632,7 @@ $$ $$ $$ Sat \begin{cases} s.t \begin{cases} p_u + p_v \geq c_{uv} \\ u \in X, v \in Y\\ p_u, p_v \geq 0 Loading docs/ds/binary-heap.md +13 −13 File changed.Contains only whitespace changes. Show changes Loading
docs/dp/index.md +6 −3 Original line number Diff line number Diff line Loading @@ -97,10 +97,13 @@ ```cpp int a[MAXN]; int dp() { int now = 0, ans = 1; int now = 1, ans = 1; for (int i = 2; i <= n; i++) { if (a[i] > a[i - 1]) ans++; now = max(now, ans); if (a[i] > a[i - 1]) now++; else now = 1; ans = max(now, ans); } return ans; } Loading
docs/graph/2-sat.md +1 −1 Original line number Diff line number Diff line > SAT 是适定性(Satisfiability)问题的简称。一般形式为 k - 适定性问题,简称 k-SAT。而当 $k>2$ 时该问题为 NP 完全的。所以我们之研究 $k=2$ 的情况。 > SAT 是适定性(Satisfiability)问题的简称。一般形式为 k - 适定性问题,简称 k-SAT。而当 $k>2$ 时该问题为 NP 完全的。所以我们只研究 $k=2$ 的情况。 ## 定义 Loading
docs/graph/index.md +8 −8 Original line number Diff line number Diff line Loading @@ -40,23 +40,23 @@ ## 结点的度数 设图 $G= \langle V,E\rangle$ 为一个有向图, $v\in V$ ,关联于结点 $v$ 的 **边** 的条数,称为点 $v$ 的度数,记作 $deg(v)$ 。 设图 $G= \langle V,E\rangle$ 为一个有向图, $v\in V$ ,关联于结点 $v$ 的 **边** 的条数,称为点 $v$ 的度数,记作 $\deg(v)$ 。 注意:一个自环为它的端点增加 2 度。 当图 $G= \langle V,E\rangle$ 为一个有向图, $v\in V$ ,称以 $v$ 作为始点的边数之和称为结点 $v$ 的出度,记为 $deg^{+} (v)$ 。将以 $v$ 作为终点的边数之和称为结点 $v$ 的入度,记为 $deg^{-} (v)$ 。称以 $v$ 作为端点的边数之和为结点 $v$ 的度数或度,记为 $deg(v)$ 。 当图 $G= \langle V,E\rangle$ 为一个有向图, $v\in V$ ,称以 $v$ 作为始点的边数之和称为结点 $v$ 的出度,记为 $\deg^{+} (v)$ 。将以 $v$ 作为终点的边数之和称为结点 $v$ 的入度,记为 $\deg^{-} (v)$ 。称以 $v$ 作为端点的边数之和为结点 $v$ 的度数或度,记为 $\deg(v)$ 。 显然, $\forall v\in V,deg(v)=deg^{+} (v)+deg^{-} (v)$ 。 显然, $\forall v\in V,\deg(v)=deg^{+} (v)+\deg^{-} (v)$ 。 ### 定理 1 $\sum_{v\in V} deg(v)=2\times |E|$ $\sum_{v\in V} \deg(v)=2\times |E|$ 推论:在任意图中,度数为奇数的点必然有偶数个。 ### 定理 2 $\sum_{v\in V} deg^{+} (v)=\sum_{v\in V} deg^{-} (v)=|E|$ $\sum_{v\in V} \deg^{+} (v)=\sum_{v\in V} \deg^{-} (v)=|E|$ 即所有点入度之和等于出度之和。 Loading @@ -78,19 +78,19 @@ 树:边数比结点数少一的连通图。更多内容,详见[树相关基础](/graph/tree-basic/)。 森林:由 $m$ 棵( $m\ge 0$ )互不相交的树组成的图。 森林:由 $m$ 棵( $m\ge 0$ )互不相交的树组成的图。 基环树:边数和点数相等的连通图。 仙人掌:每个结点至多在一个简单环上的图。 在无向图中,关联一对顶点的边多于 1 条,则称这些边为重边(平行边),重边的条数称为重数。 在无向图中,关联一对顶点的边多于 $1$ 条,则称这些边为重边(平行边),重边的条数称为重数。 简单图:不含重边和自环的图。 多重图:含重边的图。 完全图:每对不同的顶点之间都恰连有一条边相连的简单无向图。容易证明, $n$ 个顶点的完全图有 $\frac{n\times (n-1)}{2}$ 条边。 完全图:每对不同的顶点之间都恰连有一条边相连的简单无向图。容易证明, $n$ 个顶点的完全图有 $\dfrac{n(n-1)}{2}$ 条边。 竞赛图:通过在完全图中为每条边分配方向而获得的有向图。 Loading
docs/math/du-sieves.md +5 −5 Original line number Diff line number Diff line Loading @@ -67,12 +67,12 @@ $$ 那么假如我们可以快速对 $\sum_{i=1}^n(f\times g)(i)$ 求和,并用数论分块求解 $\sum_{i=2}^ng(i)S\left(\left\lfloor\frac{n}{i}\right\rfloor\right)$ 就可以在较短时间内求得 $g(1)S(n)$. ## 【例 1】模板 ## 问题一 ??? note " [P4213【模板】杜教筛(Sum)](https://www.luogu.org/problemnew/show/P4213)" 题目大意:求 $S_1(n)= \sum_{i=1}^{n} \mu(i)$ 和 $S_2(n)= \sum_{i=1}^{n} \varphi(i)$ 的值, $n\le 2^{31} -1$ 。 ### 求解 $\mu$ 前缀和 ### 莫比乌斯函数前缀和 由 **狄利克雷卷积** ,我们知道: Loading @@ -92,7 +92,7 @@ $$ 对于较大的值,需要用 `map` 存下其对应的值,方便以后使用时直接使用之前计算的结果。 ### 求解 $\varphi$ 前缀和 ### 欧拉函数前缀和 当然也可以用杜教筛求出 $\varphi (x)$ 的前缀和,但是更好的方法是应用莫比乌斯反演: Loading @@ -104,7 +104,7 @@ $$ 观察到,只需求出莫比乌斯函数的前缀和,就可以快速计算出欧拉函数的前缀和了。时间复杂度 $O(n^{\frac 2 3})$ 。 ### 使用杜教筛求解 $\varphi$ 前缀和 #### 使用杜教筛求解 求 $S(i)=\sum_{i=1}^n\varphi(i)$. Loading Loading @@ -177,7 +177,7 @@ int main() { } ``` ## 【例 2】简单的数学题 ## 问题二 ??? note " [[LuoguP3768] 简单的数学题](https://www.luogu.org/problemnew/show/P3768)" 大意:求 Loading
docs/math/simplex.md +168 −185 Original line number Diff line number Diff line Loading @@ -40,7 +40,7 @@ $$ $$ s.t \begin{cases} \sum_{j = 1}^{n}a_{ij}x_j = b_j, i = 1,2,...,m\\ \displaystyle \sum_{j = 1}^{n}a_{ij}x_j = b_j, i = 1,2,...,m\\ xj \geq 0 , j = 1,2,...,n \\ \end{cases} $$ Loading Loading @@ -71,7 +71,7 @@ $$ 标准形的形式为: - 1)目标函数要求max - 1)目标函数要求 $\max$ - 2)约束条件均为等式 Loading Loading @@ -136,7 +136,7 @@ $$ 还是通过上述具体的线性规划问题来说明: $$ max \ z = x_1 + x_2 \max \ z = x_1 + x_2 $$ $$ Loading @@ -147,7 +147,7 @@ x_1, x_2, x_3, x_4 \geq 0 \end{cases} $$ 如果选择 $x_2$ 、$x_3$ 为基变量,那么令 $x_1$、$x_4$ 等于 $0$ ,可以去求解基变量 $x_2$ 、$x_3$ 的值。对系数矩阵做行变换,如下所示,$x_2=9/2$ ,$x_3=15/2$。 如果选择 $x_2$ 、$x_3$ 为基变量,那么令 $x_1$、$x_4$ 等于 $0$ ,可以去求解基变量 $x_2$ 、$x_3$ 的值。对系数矩阵做行变换,如下所示,$x_2=9/2$ ,$x_3=15/2$。 $$ \left[\begin{array}{ccccc}{\mathrm{X}} & {x_{1}} & {x_{2}} & {x_{3}} & {x_{4}} & {b} \\ {} & {2} & {1} & {1} & {0} & {12} \\ {} & {1} & {2} & {0} & {1} & {9} \\ {\mathrm{C}} & {1} & {1} & {0} & {0} & {z}\end{array}\right] \rightarrow\left[\begin{array}{ccccc}{\mathrm{X}} & {x_{1}} & {x_{2}} & {x_{3}} & {x_{4}} & {b} \\ {} & {\frac{3}{2}} & {0} & {1} & {-\frac{1}{2}} & {\frac{15}{2}} \\ {} & {\frac{1}{2}} & {1} & {0} & {\frac{1}{2}} & {\frac{9}{2}} \\ {\mathrm{C}} & {\frac{1}{2}} & {0} & {0} & {-\frac{1}{2}} & {z-\frac{9}{2}}\end{array}\right] Loading Loading @@ -293,37 +293,30 @@ double Z; set<int> P; size_t cn, bn; bool Pivot(pair<size_t, size_t> &p)//返回0表示所有的非轴元素都小于0 { bool Pivot(pair<size_t, size_t> &p) { //返回0表示所有的非轴元素都小于0 int x = 0, y = 0; double cmax = -INT_MAX; vector<double> C = Matrix[0]; vector<double> B; for( size_t i = 0 ; i < bn ; i++ ) { for(size_t i = 0 ; i < bn ; i++) { B.push_back(Matrix[i][cn - 1]); } for( size_t i = 0 ; i < C.size(); i++ )//在非轴元素中找最大的c { if( cmax < C[i] && P.find(i) == P.end()) { for(size_t i = 0 ; i < C.size(); i++) { //在非轴元素中找最大的c if(cmax < C[i] && P.find(i) == P.end()) { cmax = C[i]; y = i; } } if( cmax < 0 ) { if(cmax < 0) { return 0; } double bmin = INT_MAX; for( size_t i = 1 ; i < bn ; i++ ) { for(size_t i = 1 ; i < bn ; i++) { double tmp = B[i] / Matrix[i][y]; if( Matrix[i][y] != 0 && bmin > tmp ) { if(Matrix[i][y] != 0 && bmin > tmp) { bmin = tmp; x = i; } Loading @@ -331,10 +324,8 @@ bool Pivot(pair<size_t, size_t> &p)//返回0表示所有的非轴元素都小于 p = make_pair(x, y); for( set<int>::iterator it = P.begin() ; it != P.end() ; it++) { if( Matrix[x][*it] != 0 ) { for(set<int>::iterator it = P.begin() ; it != P.end() ; it++) { if(Matrix[x][*it] != 0) { //cout<<"erase "<<*it<<endl; P.erase(*it); break; Loading @@ -345,12 +336,9 @@ bool Pivot(pair<size_t, size_t> &p)//返回0表示所有的非轴元素都小于 return true; } void pnt() { for( size_t i = 0 ; i < Matrix.size() ; i++ ) { for( size_t j = 0 ; j < Matrix[0].size() ; j++ ) { void pnt() { for(size_t i = 0 ; i < Matrix.size() ; i++) { for(size_t j = 0 ; j < Matrix[0].size() ; j++) { cout << Matrix[i][j] << "\t"; } cout << endl; Loading @@ -358,42 +346,33 @@ void pnt() cout << "result z:" << -Matrix[0][cn - 1] << endl; } void Gaussian(pair<size_t, size_t> p)//行变换 { void Gaussian(pair<size_t, size_t> p) { //行变换 size_t x = p.first; size_t y = p.second; double norm = Matrix[x][y]; for( size_t i = 0 ; i < cn ; i++ )//主行归一化 { for(size_t i = 0 ; i < cn ; i++) { //主行归一化 Matrix[x][i] /= norm; } for( size_t i = 0 ; i < bn && i != x; i++ ) { if( Matrix[i][y] != 0) { for(size_t i = 0 ; i < bn && i != x; i++) { if(Matrix[i][y] != 0) { double tmpnorm = Matrix[i][y]; for( size_t j = 0 ; j < cn ; j++ ) { for(size_t j = 0 ; j < cn ; j++) { Matrix[i][j] = Matrix[i][j] - tmpnorm * Matrix[x][j]; } } } } void solve() { void solve() { pair<size_t, size_t> t; while(1) { while(1) { pnt(); if( Pivot(t) == 0 ) { if(Pivot(t) == 0) { return; } cout << t.first << " " << t.second << endl; for( set<int>::iterator it = P.begin(); it != P.end() ; it++ ) { for(set<int>::iterator it = P.begin(); it != P.end() ; it++) { cout << *it << " "; } cout << endl; Loading @@ -401,16 +380,13 @@ void solve() } } int main(int argc, char *argv[]) { int main(int argc, char *argv[]) { //ifstream fin; //fin.open("./test"); cin >> cn >> bn; for( size_t i = 0 ; i < bn ; i++ ) { for(size_t i = 0 ; i < bn ; i++) { vector<double> vectmp; for( size_t j = 0 ; j < cn ; j++) { for(size_t j = 0 ; j < cn ; j++) { double tmp = 0; cin >> tmp; vectmp.push_back(tmp); Loading @@ -418,8 +394,7 @@ int main(int argc, char *argv[]) Matrix.push_back(vectmp); } for( size_t i = 0 ; i < bn-1 ; i++ ) { for(size_t i = 0 ; i < bn - 1 ; i++) { P.insert(cn - i - 2); } solve(); Loading Loading @@ -459,7 +434,7 @@ int main(int argc, char *argv[]) ### 6.1 标准型 $m+n$ 个约束 $n$ 个变量用 $x$ 向量表示,$A$ 是一个 $m*n$ 的矩阵,$c$ 是一个 $n$ 的向量,$b$ 是一个 $m$ 的向量,最大化 $cx$ 满足约束 $Ax \leq b,x > 0$。 $m+n$ 个约束 $n$ 个变量用 $x$ 向量表示,$A$ 是一个 $m\times n$ 的矩阵,$c$ 是一个 $n$ 的向量,$b$ 是一个 $m$ 的向量,最大化 $cx$ 满足约束 $Ax \leq b,x > 0$。 最大化 $\sum_{j=1}^nc_jx_j$ 满足如下约束条件: $$ Loading @@ -484,7 +459,7 @@ $$ ### 6.2 转换为标准型 若目标函数要求取最小值,那么可以对其取相反数变成取最大值。对于限制条件 $f(x_1, x_2, \ldots ,x_n) = b$,可以用两个不等式 $f(x_1, x2, \ldots, x_n) \leq b,-f(x_1,x_2,\ldots,x_n) \leq -b$ 描述,对于限制条件 $f(x_1,x_2,\ldots,x_n) \geq b$,可以用不等式 $-f(x_1,x_2,\ldots,x_n) \leq -b$ 描述。对于无限制的变量 $x$,可以将其拆为两个非负变量 $x_0,x_1$,使得 $x = x_0 - x_1$。 若目标函数要求取最小值,那么可以对其取相反数变成取最大值。对于限制条件 $f(x_1, x_2, \ldots ,x_n) = b$,可以用两个不等式 $f(x_1, x_2, \ldots, x_n) \leq b,-f(x_1,x_2,\ldots,x_n) \leq -b$ 描述,对于限制条件 $f(x_1,x_2,\ldots,x_n) \geq b$,可以用不等式 $-f(x_1,x_2,\ldots,x_n) \leq -b$ 描述。对于无限制的变量 $x$,可以将其拆为两个非负变量 $x_0,x_1$,使得 $x = x_0 - x_1$。 ### 6.3 松弛型 Loading @@ -505,15 +480,15 @@ $$ ### 6.5 可行解 - 基本解:所有非基变量设为0,基本变量为右侧的常数 - 基本解:所有非基变量设为 $0$,基本变量为右侧的常数 - 基本可行解:所有 $b_i \geq 0$ - 基本可行解:所有 $b_i \geq 0$ > 注:单纯形法的过程中B和N不断交换,在n维空间中不断走,“相当于不等式上的高斯消元”。 ### 6.6 转轴 选取一个非基本变量 $x_e$ 为替入变量,基本变量 $x_l$ 为替出变量,将其互换,为了防止循环,根据 **Bland规则** ,选择下标最小的变量。 选取一个非基本变量 $x_e$ 为替入变量,基本变量 $x_l$ 为替出变量,将其互换,为了防止循环,根据 **Bland规则** ,选择下标最小的变量。 > **Bland规则** 可以参看:[最优化方法](https://github.com/AngelKitty/review_the_national_post-graduate_entrance_examination/blob/master/books_and_notes/professional_courses/data_structures_and_algorithms/sources/extra_books/%E6%9C%80%E4%BC%98%E5%8C%96%E6%96%B9%E6%B3%95.pdf) Loading @@ -534,24 +509,24 @@ $$ 基本思想就是改写 $l$ 这个约束为 $x_e$ 作为基本变量,然后把这个新 $x_e$ 的值带到其他约束和目标函数中,就消去 $x_e$ 了。改写和带入时要修改 $b$ 和 $a$,目标函数则是 $c$ 和 $v$。 转动时,$l$ 和 $e$ 并没有像算法导论上一样,$a$ 矩阵用了两行分别是 $a[l][ \ ]$和 $a[e][ \ ]$(这样占用内存大),而是用了同一行,这样 $a$ 矩阵的行数 $=|B|$,列数 $=|N|$。 转动时,$l$ 和 $e$ 并没有像算法导论上一样,$a$ 矩阵用了两行分别是 $a_{l, \square}$ 和 $a_{e, \square}$(这样占用内存大),而是用了同一行,这样 $a$ 矩阵的行数 $=|B|$,列数 $=|N|$。 也就是说,约束条件只用 $m$ 个,尽管 $B$ 和 $N$ 不断交换,但同一时间还是只有 $m$ 个约束(基本变量),$n$ 个非基变量,注意改写成松弛型后 $a$ 矩阵实际系数为负。(一个优化 $a[i][e]$为 $0$ 的约束没必要带入了。 也就是说,约束条件只用 $m$ 个,尽管 $B$ 和 $N$ 不断交换,但同一时间还是只有 $m$ 个约束(基本变量),$n$ 个非基变量,注意改写成松弛型后 $a$ 矩阵实际系数为负。(一个优化为 $a_{i,e}$ 的约束没必要带入了。 `simplex` 是主过程,基本思想是找到一个 $c[e]>0$ 的,然后找对这个 $e$ 限制最紧的 $l$ ,转动这组 $l,e$,注意精度控制 $eps$,$c[e]>eps$, 还有找 $l$ 的时候 $a[i][e]>eps$ 才行。 `simplex` 是主过程,基本思想是找到一个 $c_e>0$ 的,然后找对这个 $e$ 限制最紧的 $l$ ,转动这组 $l,e$,注意精度控制 $\epsilon$,$c_e>\epsilon$, 还有找 $l$ 的时候 $a_{i,e}>\epsilon$ 才行。 ??? note " 例题 [BZOJ1061 志愿者招募](https://www.lydsy.com/JudgeOnline/problem.php?id=1061)" 题目大意:长度为 $n$ 的序列,第 $i$ 位至少 $b_i$,$m$ 种区间使 $[l_i,r_i] + 1$ 代价为 $a_i$。 题目大意:长度为 $n$ 的序列,第 $i$ 位至少 $b_i$,$m$ 种区间使 $[l_i,r_i] + 1$ 代价为 $a_i$。 原始问题 $m$ 个变量,$n$ 个约束,当 $l_j \leq i \leq r_j$,$a_{ij} = 1$。 原始问题 $m$ 个变量,$n$ 个约束,当 $l_j \leq i \leq r_j$,$a_{ij} = 1$。 对偶问题 $n$ 个变量,$m$ 个约束 对偶问题 $n$ 个变量,$m$ 个约束 $$ \max \ \sum_{i=1}nb_iy_i $$ $$ Sat \ \sum_{l_i \leq j \leq r_i}y_j \leq c_i, y_i \geq 0 s.t \ \sum_{l_i \leq j \leq r_i}y_j \leq c_i, y_i \geq 0 $$ 把对应出的系数矩阵带入到单纯形算法就可以求出最优解了。 Loading @@ -567,9 +542,16 @@ typedef long long ll; const int M = 10005, N = 1005, INF = 1e9; const double eps = 1e-6; inline int read() { char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();} char c = getchar(); int x = 0, f = 1; while(c < '0' || c > '9') { if(c == '-')f = -1; c = getchar(); } while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); } return x * f; } Loading Loading @@ -607,7 +589,8 @@ double simplex(){ } int main() { n=read();m=read(); n = read(); m = read(); for(int i = 1; i <= n; i++) c[i] = read(); for(int i = 1; i <= m; i++) { int s = read(), t = read(); Loading Loading @@ -636,7 +619,7 @@ $$ $$ $$ Sat \begin{cases} s.t \begin{cases} \sum_{(v) \in Y} d_{uv} \leq 1, u \in X \\ \sum_{(u) \in X} d_{uv} \leq 1, v \in Y \\ d_{u,v} \in \{0,1\} Loading @@ -649,7 +632,7 @@ $$ $$ $$ Sat \begin{cases} s.t \begin{cases} p_u + p_v \geq c_{uv} \\ u \in X, v \in Y\\ p_u, p_v \geq 0 Loading