首页 > 其他分享 >状态压缩 dp

状态压缩 dp

时间:2024-07-24 22:07:27浏览次数:14  
标签:状态 cnt int 压缩 state include dp

\(\texttt{0x00}\):概念

状压 DP 是动态规划的一种,通过将状态压缩为整数来达到优化转移的目的。

$\text{----OI Wiki}$

简单说来,就是我们通过普通的状态表示无法直接推出状态转移方程了,这时候将当前状态拓展的“轮廓”作为状态表示的一维,而考虑到空间复杂度和计算机原理,主要使用二进制压缩,当然你也可以格局打开使用三进制乃至其他进制。

状态压缩 dp 有一个很明显的特征:数据范围比较小且一般在 \(20\) 以下。

\(\texttt{0x01}\):例题

1. 填充网格型

AcWing 291. 蒙德里安的梦想

题目大意

给定一个 \(N\times M\) 的网格,求用 \(1\times 2\) 和 \(2\times 1\) 的长方形去铺满它有多少种方案。

数据范围:\(N,M\le 11\)

思路:

考虑怎么放才能刚好填满网格。

可以想到,如果先放横着的,再放竖着的,那么当我们将横着的都放完后,若竖着的恰好能刚好嵌进去,说明这是一个合法方案。

也就是说,放完横着的矩形后放竖着的矩形的方法的唯一确定的,那么:

求总的方案数其实就是求横着放且合法(使竖着的能嵌进去刚好铺满网格)的方案数。

因为放横着的矩形时拓展的方向是横向的,就是说我们放矩形时,当前放的这个矩形只影响到下一列,这启示我们将“列号”作为 dp 的阶段,同时由于上一列的放置情况会影响到当前这一列,所以我们需要将上一列伸出来的部分作为状态中的一维才能转移。

那么如何表示上一列那些地方伸出来了呢?

如果用 bool 数组来表示第 \(i\) 行有没有伸出来,不仅效率低下,而且不方便计算,这时候状态压缩就来了:采用二进制压缩,相当于将原来的 bool 数组变成一个二进制数 state,state 的第 \(i\) 位表示第 \(i\) 是否伸出,\(0\) 表示未伸出,\(1\) 表示伸出。

设 \(f(i, state)\) 表示已经摆完了前 \(i - 1\) 列,且从第 \(i - 1\) 列伸到第 \(i\) 列的方案数,那么状态转移方程为:

\[f(i, state) = \sum f(i - 1, last\_state) \]

其中 \(last\_state\) 是第 \(i - 2\) 列伸到第 \(i - 1\) 的状态,且需要满足 \(last\_state\) 对于 \(state\) 合法。

\(last\_state\) 对于 \(state\) 合法当且仅当以下两个条件满足:

  1. state & last_state == 0,即第 \(i - 2\) 列伸到第 \(i - 1\) 的小方格和 \(i - 1\) 列放置的小方格不重复;
  2. 每一列,所有连续着空着的小方格必须是偶数个,因为竖着的矩形必须要能嵌入。

初始化:\(f(0,0) = 1\)。

按定义这里是:前第 \(-1\) 列都摆好,且从第 \(-1\) 列到第 \(0\) 列伸出来的状态为 \(0\) 的方案数。
首先,这里没有 \(-1\) 列,最少也是 \(0\) 列。
其次,没有伸出来,即没有横着摆的。即这里第 \(0\) 列只有竖着摆这 \(1\) 种状态。

目标:\(f(m,0)\)。

\(f(m, 0)\) 表示前 \(m - 1\) 列都处理完,并且第 \(m - 1\) 列没有伸出来的所有方案数。
即整个棋盘处理完的方案数。

再用集合划分的思想来解释一下。

首先要“化零为整”,即用一个集合表示一类情况,对于这道题,假设我们放矩形时是对于每列都从上往下放,那么可以根据当前放到了第几列来划分集合。

但这样划分我们无法找到各个集合之间的转移关系,所以还要再划分一次。

集合划分的依据就是寻找集合中元素的不同点,发现在摆完前 \(i - 1\) 列的方案中向第 \(i\) 列伸出的情况不同,所以可以以此来划分。

所以状态表示为:\(f(i, state)\) 表示已经摆完了前 \(i - 1\) 列,且从第 \(i - 1\) 列伸到第 \(i\) 列的方案数。

接着就是“化整为零”的过程,即状态计算,同上。

\(\texttt{Talk is cheap, show you the code.}\)

#include <vector>
#include <cstring>
#include <iostream>

using namespace std;

const int N = 12, M = 1 << N;
typedef long long ll;
int n, m;
vector<int> tran[M];
ll dp[N][M];
bool st[M];

bool check(int x) { //判断该状态是否满足所有连续着空着的小方格必须是偶数个
    int cnt = 0;
    for(int i = 0; i < n; i++) {
        if(x >> i & 1) {
            if(cnt & 1) return false;
            cnt = 0;
        }
        else ++cnt;
    }
    if(cnt & 1) return false;
    return true;
}

int main() {
    while(scanf("%d%d", &n, &m), n || m) {
        for(int i = 0; i < 1 << n; i++) st[i] = check(i); //提前预处理那哪些状态是合法的
        
        for(int i = 0; i < 1 << n; i++) {
            tran[i].clear();  //多测清空
            for(int j = 0; j < 1 << n; j++)
                if(!(i & j) && st[i | j])
                    tran[i].push_back(j); //提前预处理出每个可行状态能由那些状态转移过来
        }
        
        memset(dp, 0, sizeof dp);
        dp[0][0] = 1;
        for(int i = 1; i <= m; i++)
            for(int j = 0; j < 1 << n; j++)
                for(int k = 0; k < tran[j].size(); k++)
                    dp[i][j] += dp[i - 1][tran[j][k]];
        printf("%lld\n", dp[m][0]);
    }
    return 0;
}

P1896 [SCOI2005] 互不侵犯

题目大意

在一个 \(n∗n\) 的图中选 \(k\) 个点,使得以每个点为中心的九宫格内有且只有它一个点,问方案数。

数据范围:\(1\le n\le 9,\space 0\le k\le n * n\)。

思路

题型和第一道例题差不多。

分析可以发现,如果我们从上往下一排一排地放国王,那么当前这一行放国王的方式只取决于上一行,所以行数可以作为状态的一维。

于是乎我们可以考虑把排数 \(i\) 作为动态规划的“阶段”进行线性 dp。

接着我们需要上一行的摆放状态来推出这一行,所以它也要作为一维。

题目要求摆放 \(k\) 个国王,所以摆放了多少个国王也应该作为一维。

综上所述,状态表示为 \(f(i, j, k)\),表示已经放了前 \(i\) 排,放了 \(j\) 个国王,第 \(i\) 排状态为 \(k\) 的方案数。

则状态转移方程为:

\[f(i, j, k) = \sum f(i - 1, j - cnt(k), state) \]

其中 \(state\) 表示第 \(i - 1\) 排的状态,\(cnt(k)\) 表示 \(k\) 这个状态包含多少个国王,即第 \(i\) 排摆了多少国王。

如果直接枚举所有状态时间复杂度为 \(O(n ^ 3 * K * 4 ^ n)\),不能接受。

发现其实状态很多都是不合法的,所以可以提前预处理出合法状态,这样的枚举量就会小很多。

同时可以预处理出每个状态可以由哪些状态转移过来,进一步优化转移过程。

虽然状态很多,但是合法状态并不多,合法的转移状态更不多。

接下来就要看怎么判断状态合法。

用 \(1\) 代表放了国王,\(0\) 表示没放,所以很容易想到,在一排的状态中不能出现连续的 \(1\)。
预处理相邻排的状态时要注意国王不能位于另一个国王的九宫格内,所以国王的列号不能相邻

设第 \(i\) 排的状态为 \(j\),第 \(i - 1\) 的状态为 \(k\),即 \(j,k\) 要满足:

  1. \(j,k\) 都没有连续的 \(1\);
  2. \(j \operatorname{or} k\) 没有连续的 \(1\)。

初始化:\(f(0, 0, 0) = 1\)。(什么都不摆也是一种方案)
目标:\(f(n + 1, m, 0)\)。(一个小 \(\texttt{tip}\),所有的方案数等价于摆完了 \(n + 1\) 排且摆了 \(m\) 个国王(第 \(n + 1\) 排什么都没摆))

\(\texttt{Talk is cheap, show you the code.}\)

#include <vector>
#include <iostream>

using namespace std;

const int N = 12, M = N * N;
typedef long long ll;
int n, m;
int cnt[1 << N]; //储存每个状态中有多少个国王
vector<int> state; //记录所有的合法状态
vector<int> tran[1 << N]; //记录每一个合法状态能由那些状态转移到
ll dp[N][M][1 << N];

bool check(int x) {
    for(int i = 0; i < n; i++)
        if((x >> i & 1) && (x >> (i + 1) & 1)) return false;
    return true;
}

int count(int x) {
    int res = 0;
    for(int i = 0; i < n; i++) res += x >> i & 1;
    return res;
}

int main() {
    scanf("%d%d", &n, &m);
    for(int i = 0; i < 1 << n; i++)
        if(check(i)) {
            state.push_back(i);
            cnt[i] = count(i);
        }
    
    for(int i = 0; i < state.size(); i++)
        for(int j = 0; j < state.size(); j++) {
            int a = state[i], b = state[j];
            if((a & b) == 0 && check(a | b))
                tran[i].push_back(j);
        }
            
    dp[0][0][0] = 1;
    for(int i = 1; i <= n + 1; i++)
        for(int j = 0; j <= m; j++)
            for(int a = 0; a < state.size(); a++)
                for(int b = 0; b < tran[a].size(); b++) {
                    int c = cnt[state[a]];
                    if(j >= c)
                        dp[i][j][state[a]] += dp[i - 1][j - c][state[tran[a][b]]];
                }
    printf("%lld", dp[n + 1][m][0]); //一个小 tip,所有的方案数等价于摆完了 n + 1 排且摆了 m 个国王(第 n + 1 排什么都没摆)
    return 0;
}

P2704 [NOI2001] 炮兵阵地

题目描述

给定一个 \(N\times M\) 矩阵,矩阵中标有 \(H\) 字样的位置不能放置棋子,标有 \(P\) 字样的位置可以放置棋子。

棋子的攻击方向为上、下、左、右四个方向,攻击距离为 \(2\) 个格子。

现在在该棋盘上放置棋子,使得棋子之前不能被互相攻击到,能够放置棋子的最大个数。

数据范围:\(N\le 100, M\le 10\)。

思路

和上一道题很像,但这道题的攻击距离变成了 \(2\),所以我们还需要 \(i - 2\) 行的状态。

和上一道题一样先预处理出合法的状态,即满足每三位都不能有超过 \(2\) 个 \(1\),储存在 \(state\) 中。
从中可以看出这道题的合法状态比上一道题还要少。

还是可以考虑把行数 \(i\) 作为动态规划的“阶段”进行线性 dp。

状态表示:\(f(i, j, k)\) 表示已经摆完前 \(i\) 行,且第 \(i - 1\) 行的状态为 \(j\),第 \(i\) 行的状态为 \(k\) 的最大棋子放置数量。

状态转移方程为:

\[f(i, j, k) = \max\{f(i - 1, s, j) + cnt(b)\} \]

其中 \(j,k\) 都是下标,\(s\) 是枚举的第 \(i - 2\) 行的状态的下标,\(b = state[k]\),\(cnt(b)\) 表示 \(b\) 这个状态含有多少个棋子。

定义 \(H\) 为 \(1\),\(P\) 为 \(0\),则整个地图可以看作 \(N\) 个 \(M\) 位的二进制数。

设 \(a = state(j), b = state(k), c = state(s)\),那么 \(a,b,c\) 都要合法才行,根据题意,它们应该满足以下条件:

  1. a & b | a & c | b & c = 0 表示每个棋子都不能互相攻击到对方
  2. g[i - 1] & a | g[i] & b = 0 表示只有 \(P\) 才能放棋子(若在 \(H\) 上放棋子了,按位与结果一定不为 \(0\))

算一算,要开 \(100 * 1024 * 1024 = 104,857,600 \approx 10^8\) 的数组,空间直接爆炸!

那怎么办呢?

注意到第一维每次只会用到上一层的状态,所以可以滚动数组。
小技巧:在原来的基础上加上滚动数组只需要把那一维全加上 & 1 就行了。

初始化:\(f(0, 0, 0) = 0\)。(什么都不摆最大数量显然为 \(0\))
目标:\(f(n + 2, 0, 0)\)。(同上题:循环到 \(n + 2\) 且后两维都为 \(0\) 表示 \(n + 1\) 和 \(n + 2\) 行什么都没放,等价于在全局最大值)

\(\texttt{Talk is cheap, show you the code.}\)

#include <vector>
#include <cstring>
#include <iostream>

using namespace std;

const int N = 110, M = 1 << 10;

int n, m;
int g[N];
vector<int> state;
int cnt[M];
int dp[2][M][M]; //滚动数组

bool check(int x) { //检查合法状态:每三位都不能有超过 2 个 1
    for(int i = 0; i < m; i++)
        if((x >> i & 1) && ((x >> i + 1 & 1) || (x >> i + 2 & 1))) return false;
    return true;
}

int count(int x) { //统计每个状态中放棋子的个数
    int res = 0;
    for(int i = 0; i < m; i++) res += x >> i & 1;
    return res;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    cin >> n >> m;
    char c;
    for(int i = 1; i <= n; i++) {
        for(int j = 0; j < m; j++) {
            cin >> c; //遇到这种字符读入还没有空格的题,还是用 cin 吧
            if(c == 'H') g[i] += 1 << j;
        }
    }
    
    for(int i = 0; i < 1 << m; i++) //预处理合法状态
        if(check(i)) {
            state.push_back(i);
            cnt[i] = count(i);
        }
	
    for(int i = 1; i <= n + 2; i++)
        for(int j = 0; j < state.size(); j++) //注意 j, k, t 都是下标
            for(int k = 0; k < state.size(); k++)
                for(int t = 0; t < state.size(); t++) {
                    int a = state[j], b = state[k], c = state[t];
                    if(a & b | a & c | b & c) continue; //检查合法性
                    if(g[i - 1] & a | g[i] & b) continue;
                    dp[i & 1][j][k] = max(dp[i & 1][j][k], dp[i - 1 & 1][t][j] + cnt[b]);
                }
    
    cout << dp[n + 2 & 1][0][0] << '\n'; //同上题:循环到 n + 2 且后两维都为 0 表示 n + 1 和 n + 2 行什么都没放,等价于在全局最大值
    return 0;    
}

2. 集合划分型


P10447 最短 Hamilton 路径

题目描述

已经很清楚就不给了。

思路

容易想到一种朴素做法:枚举所有可能的方案即枚举 \(n\) 的全排列,然后算最短路径,时间复杂度为 \(O(n * n!)\)。

实际上这个过程可以用二进制状态压缩来优化。因为我们只关心方案最优解,而不关心具体方案,所以我们只需要记录当前这个方案的最优解即可,那么我们考虑的状态,就只有:在当前方案 \(i\) 中,目前抵达的点是 \(j\)。

也就是说,我们用一个状态代表一个集合,集合是一类方案的总和。

而这个方案就是目前哪些点走过,哪些还没走过,用一个 \(n\) 位的二进制数来表示。

综上所述,令 \(f(i, j)\) 来表示当前状态为 \(i\),停留的最后一个点为 \(j\) 的方案的最短距离,那么状态转移方程为:

\[f(i, j) = \min\{f(i, j), f(i\operatorname{xor}2 ^ j, k) + weight(k, j)\} \]

初始化:\(f(1, 0) = 0\)。(从第一个点出发,状态为 \(1\),走过的距离为 \(0\))
目标:\(f(2 ^ n - 1, n - 1)\)。(下标从 \(0\) 开始,全部走完且最后停在第 \(n\) 个点)

\(\texttt{Talk is cheap, show you the code.}\)

#include <cstring>
#include <iostream>

using namespace std;

const int N = 20;

int n;
int g[N][N];
int dp[1 << N][N];

int main() {
    scanf("%d", &n);
    for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++)
            scanf("%d", &g[i][j]);
    
    memset(dp, 0x3f, sizeof dp);
    dp[1][0] = 0;
    for(int i = 1; i < 1 << n; i++)
        for(int j = 0; j < n; j++)
            if(i >> j & 1) //枚举的这个状态必须要经过 j 才行
                for(int k = 0; k < n; k++)
                    if(i >> k & 1) //枚举的这个状态也必须要经过 k 才行
                        dp[i][j] = min(dp[i][j], dp[i - (1 << j)][k] + g[k][j]);
                        
    printf("%d", dp[(1 << n) - 1][n - 1]);
    return 0;
}

P2831 [NOIP2016 提高组] 愤怒的小鸟

题目大意

多组数据,在一个二维平面上,每组数据给出 \(n\) 只小猪的坐标,需要用小鸟去消灭他们,每只小鸟的运动轨迹都为一条过原点的抛物线,一只小猪被消灭当且仅当:至少一只小鸟的抛物线经过该小猪的坐标,小鸟的抛物线可以自定,问:最少需要几只小鸟才能将所有的小猪消灭。

数据范围:\(n\le 18\)。

思路:

抛物线的一般方程为 \(y = ax^2 + bx + c\)。

题目中的抛物线有两个特点:

  1. 过原点, 即 \(c = 0\)。
  2. 开口向下,即 \(a < 0\)。

因此抛物线方程为:\(y = ax ^ 2 + bx\),有两个未知数,因此两点即可确定一条抛物线。

设这两点为 \((x_1, y_1), (x_2, y_2)\),相当于解方程:

\[\begin{cases} ax_1^2 + bx_1 = 0 \\ ax_2^2 + bx_2 = 0 \end{cases} \]

解得:

\[\begin{cases} a = \frac{\frac{y_1}{x_1} - \frac{y_2}{x_2}}{x_1 - x_2} \\ b = \frac{y_1}{x_1} - ax_1 \end{cases} \]

因此最多有 \(n ^ 2\) 个不同的抛物线。接下来求出所有不同的抛物线,及其能覆盖的所有点的点集。

所以这道题就变成了“重复覆盖问题”

首先想到暴搜思路:

我们可以先预处理出这 \(n ^ 2\) 条抛物线的解析式,并预处理出每一条抛物线能覆盖哪些小猪。
在搜索时若使用了一条抛物线,就把当前状态按位或上该抛物线能覆盖的小猪状态,表示当前那些小猪被覆盖了。

这样的话,对于一个还没被覆盖的小猪,我们只能开一条新的抛物线去覆盖它。

void dfs(int state, int cnt) { // state 表示当前小猪被覆盖的情况,cnt 表示已经用的小鸟数量
	if(cnt >= cnt) return ; //最优性剪枝
	if(state == (1 << n) - 1) { //若全部覆盖,则更新答案
		res = min(res, cnt);
		return ;
	}
	枚举还没被覆盖的小猪
		枚举能覆盖它的抛物线
			dfs(state | 该抛物线能覆盖的小猪, cnt + 1);
}

然后我们会惊奇地发现,如果 \(state\) 一定,那么 dfs 的结果是一定的,那就启示我们可以用状压 dp 来优化这个过程。

根据搜索的思路,设 \(f(i)\) 表示小猪被覆盖的情况为 \(i\) 时需要的最少的小鸟数量。

状态计算:找到 \(i\) 状态下没有被消灭的小猪的编号 \(x\),枚举可消灭它的抛物线 \(path_{x, j}\) 并更新状态:

\[f(i\operatorname{or} path_{x,j}) = \min\limits_{0 < j < n}\{f(i) + 1\} \]

初始化:\(f(0) = 0\) 其余都为正无穷。(没有消灭任何小猪的最少小鸟数显然为 \(0\),求最小值初始化成正无穷)
目标:\(f(2 ^ n - 1)\)。(全被消灭的最少小鸟数)

时间复杂度为 \(O(T(n ^ 3 + n * 2 ^ n))\)。

\(\texttt{Talk is cheap, show you the code.}\)

#include <cmath>
#include <vector>
#include <cstring>
#include <iostream>

using namespace std;

const int N = 20, M = 1 << 18;
const double eps = 1e-9;

int T;
int n, m;
struct node{
    double x, y;
}pig[N];
int path[N][N]; //过点i和j的抛物线过哪些点
int dp[M];

int check(double x, double y) { //浮点数存在精度误差,所以需要注意
    if(fabs(x - y) < eps) return 0;
    if(x < y) return -1;
    return 1;
}

int main() {
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d", &n, &m);
        for(int i = 0; i < n; i++) scanf("%lf%lf", &pig[i].x, &pig[i].y);
        for(int i = 0; i < n; i++) {
            path[i][i] = 1 << i; //初始态,单独生成一条只经过 (0, 0) 和 (x, y) 的抛物线
            for(int j = i + 1; j < n; j++) {
                double x1 = pig[i].x, y1 = pig[i].y;
                double x2 = pig[j].x, y2 = pig[j].y;
                if(!check(x1, x2)) continue;
                double a = (y1 / x1 - y2 / x2) / (x1 - x2);
                if(check(a, 0) >= 0) continue; // a < 0
                double b = y1 / x1 - a * x1;
                int state = 0;
                for(int k = 0; k < n; k++) { //预处理当前这条抛物线能过哪些点
                    double x = pig[k].x, y = pig[k].y;
                    if(!check(a * x * x + b * x, y)) state += (1 << k);
                }
                path[i][j] = state;
            }
        }
        memset(dp, 0x3f, sizeof dp);
        dp[0] = 0;
        for(int i = 0; i + 1 < 1 << n; i++) {
            int x;
            for(int j = 0; j < n; j++) //随便找一个未被覆盖的点
		/*
		q: 为什么只找一个呢,搜索时不是都要找并且都要搜一遍吗?
		a: 因为我们采用了状压 dp,状态表示的是一类方案,并不关心它的顺序,而且反正我们最后都要覆盖,所以随便找一个就好了
		*/
                if(!(i >> j & 1)) {
                    x = j;
                    break;
                }
            
            for(int j = 0; j < n; j++)
                dp[i | path[x][j]] = min(dp[i] + 1, dp[i | path[x][j]]);
        }
        printf("%d\n", dp[(1 << n) - 1]);
        memset(path, 0, sizeof path); //记得多测清空
    }
    
    return 0;
}

最后浅浅地整理了一些题:

填充网格型

P1879 [USACO06NOV] Corn Fields G
P5005 中国象棋 - 摆上马
P8756 [蓝桥杯 2021 省 AB2] 国际象棋
P1539 [TJOI2011] 01矩阵

集合划分型

P3092 [USACO13NOV] No Change G (不用寻常思路的状态设计)
P1433 吃奶酪
P1278 单词游戏 (注意 dp 阶段即循环顺序)
P3694 邦邦的大合唱站队 (还是要想想,思路不太明显)
P3118 [USACO15JAN] Moovie Mooving G
P5911 [POI2004] PRZ (枚举子集)
P2915 [USACO08NOV] Mixed Up Cows G

标签:状态,cnt,int,压缩,state,include,dp
From: https://www.cnblogs.com/Brilliant11001/p/18319107

相关文章

  • Wordpress安装到win10(2024年7月)
    目录1.wordpress介绍2下载应用2.1.wordpress2.2XAMPP 2.3PHPmyadmin3.配置应用3.1XAMPP进程3.2文件配置3.3phpmyadmin配置4.配置网页4.1数据库创建 4.2安装wordpress5.进入面板6.总结1.wordpress介绍WordPress是一个开源内容管理系统(CMS),它允许用户构......
  • 不存在的压缩包
    压缩包学习入门本篇只讲解Misc压缩包部分相关知识,具体原理不进行阐述。密码爆破ARCHPR选择Brute-force下方有爆破字符的选择。点击Start即可开始爆破。掩码爆破如图所谓掩码爆破就是你知道部分密码,来爆破剩下的密码。用?来表示未知符号。明文爆破所谓明文工具是指......
  • 在K8S中,我们公司用户反应pod连接数非常多,希望看一下这些连接都是什么信息?什么状态?怎么
    在K8S中,当用户反映Pod连接数非常多时,为了查看这些连接的具体信息和状态,并考虑到容器内没有集成bash环境和网络工具的情况,可以采取以下步骤进行排查:一、确认问题并收集信息查看Pod状态:使用kubectlgetpods命令查看Pod列表,确认哪个Pod的连接数异常。使用kubectldescribepod......
  • 【ABAP】-上传文件压缩后下载
    主要用到了xsting和binary之间的转换以及gui的操作代码如下*&---------------------------------------------------------------------**&Reportzpr_zip_file*&---------------------------------------------------------------------**&*&-----------------------......
  • 解决wordpress媒体上传一张图片裁剪成多张的问题
    问题在使用wordpress的媒体库的过程中我发现,我上传一张图片,但是在服务器的文件中会自动裁剪处多张不同尺寸的图片,这样在不需要的情况下,会造成存储压力解决1.wordpress后台设置打开wordpress的后台设置→媒体把这里的勾选去掉然后保存更改2.代码内修改代码文件路径/wp-con......
  • php使用ZipArchive解压压缩包
    //处理照片压缩包$zip=new\ZipArchive();//获取压缩包内容照片数量$path='static/oa/img/staImport/'.date('Ymd').'/'.date('His');if($zip->open($param['fileUrl'])===TRU......
  • Linux获取线程调度策略pthread_attr_getschedpolicy
    thread_attr_getschedpolicy 函数是POSIX线程(pthread)库中用于获取线程属性对象中的调度策略的函数。在实时系统中,调度策略决定了线程如何被调度器选择来执行。pthread_attr_getschedpolicy 函数允许你查询一个已创建的线程属性对象(pthread_attr_t 类型)中设置的调度策略......
  • 五、IPv6基础知识-NDP
    NDP:IPv6邻居发现协议,主要通过ICMPv6报文来实现其功能。1.主要功能 NDP功能对应实现的ICMPv6报文如下:2.路由发现功能 1.路由器发现是指主机发现本地链路上路由器和确定其配置信息的过程。2.路由器发现可以同时实现以下3个功能:路由器发现(RouterDiscovery):主机定位邻......
  • vue的属性绑定/条件渲染/列表渲染/key管理状态/事件处理/事件传参/事件修饰符等知识总
    1.属性绑定属性绑定使用v-bind命令执行,可忽略不写,以下图片为属性绑定知识内容效果图2.条件渲染条件渲染使用v-if命令执行**v-ifVSv-show区别**v-if是"真实的"按条件渲染,因为它确保了在切换时,条件区块内的事件监听器和子组件都会被销毁与重建(将条件移除和添加如果首次......
  • 通过微软证书服务器自签名证书替换VMware vCenter证书:达到域内主机访问vCenter Server
    通过微软证书服务器自签名证书替换VMwarevCenter证书:达到域内主机访问vCenterServer是信任状态开始之前的必要条件是已经搭建好微软AD域和对应的证书服务器。确认这些都没有问题,才可以继续下一步操作。已经通过域名的形式安装好了vCenterServer,并且可以正常访问。整体操......