Commit d632929d authored by sshwy's avatar sshwy
Browse files

Merge branch 'master' into Euclidean-like

parents 5819736a feb3cf27
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -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;
}
+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$ 的情况。

## 定义

+8 −8
Original line number Diff line number Diff line
@@ -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|$ 

即所有点入度之和等于出度之和。

@@ -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}$ 条边。

竞赛图:通过在完全图中为每条边分配方向而获得的有向图。

+5 −5
Original line number Diff line number Diff line
@@ -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$ 前缀和
### 莫比乌斯函数前缀和

**狄利克雷卷积** ,我们知道:

@@ -92,7 +92,7 @@ $$

对于较大的值,需要用 `map` 存下其对应的值,方便以后使用时直接使用之前计算的结果。

### 求解 $\varphi$ 前缀和
### 欧拉函数前缀和

当然也可以用杜教筛求出 $\varphi (x)$ 的前缀和,但是更好的方法是应用莫比乌斯反演:

@@ -104,7 +104,7 @@ $$

观察到,只需求出莫比乌斯函数的前缀和,就可以快速计算出欧拉函数的前缀和了。时间复杂度 $O(n^{\frac 2 3})$ 。

### 使用杜教筛求解 $\varphi$ 前缀和
#### 使用杜教筛求解

求 $S(i)=\sum_{i=1}^n\varphi(i)$.

@@ -177,7 +177,7 @@ int main() {
}
```

## 【例 2】简单的数学题
## 问题二

??? note " [[LuoguP3768] 简单的数学题](https://www.luogu.org/problemnew/show/P3768)"
    大意:求
+168 −185
Original line number Diff line number Diff line
@@ -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}
$$
@@ -71,7 +71,7 @@ $$

标准形的形式为:

- 1)目标函数要求max
- 1)目标函数要求 $\max$

- 2)约束条件均为等式

@@ -136,7 +136,7 @@ $$
还是通过上述具体的线性规划问题来说明:

$$
max \ z = x_1 + x_2
\max \ z = x_1 + x_2
$$

$$
@@ -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]
@@ -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;
		}
@@ -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;
@@ -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;
@@ -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;
@@ -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);
@@ -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();
@@ -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$ 满足如下约束条件:
$$
@@ -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 松弛型

@@ -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)

@@ -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
$$

把对应出的系数矩阵带入到单纯形算法就可以求出最优解了。
@@ -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;
}

@@ -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();
@@ -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\}
@@ -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
+13 −13

File changed.

Contains only whitespace changes.

Loading