状压dp详解,棋盘式、集合型,OJ详解

文章目录

    • 零、引例-小国王
      • 1.问题描述
      • 2.暴力枚举
      • 3.多维dp
      • 4.维度压缩
    • 一、状压dp
      • 1.认识状压dp
      • 2.棋盘式(基于连通性)
        • 2.1小国王
          • 2.1.1题目链接
          • 2.1.2思路分析
          • 2.1.3AC代码
        • 2.2玉米田
          • 2.2.1题目链接
          • 2.2.2思路分析
          • 2.2.3AC代码
        • 2.3炮兵阵地
          • 2.3.1题目链接
          • 2.3.2思路分析
          • 2.3.3AC代码
        • 2.4蒙德里安的梦想
          • 2.4.1题目链接
          • 2.4.2思路分析
          • 2.4.3AC代码
      • 3.集合
        • 3.1 递归实现指数型枚举
        • 3.1.1题目链接
        • 3.1.2思路分析
        • 3.1.3AC代码
      • 3.2最短Hamilton路径
        • 3.2.1题目链接
        • 3.2.2思路分析
        • 3.2.3AC代码
      • 3.3毕业旅行问题
        • 3.3.1题目链接
        • 3.3.2思路分析
        • 3.3.3AC代码
      • 3.4 愤怒的小鸟
        • 3.4.1题目链接
        • 3.4.2思路分析
        • 3.4.3AC代码


零、引例-小国王

1.问题描述

在 5×5 的棋盘里面放 K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共 8 个格子。

2.暴力枚举

考虑到每个位置有放或不放两种情况,一共64个格子,那么有264种情况,每种情况要遍历每一个位置判断是否合法,故而要计算225 * 25 = 838860800次,效率过于低下,考虑优化

3.多维dp

考虑到每一行放置方案和上一行都有关系,所以定义状态f(i, j, a, b, c, d, e)表示前i行放置j个国王,第i行放置情况为(a, b, c, d, e)分别代表第1、2、3、4、5列是否放国王,0代表不妨,1代表放

有转移方程:
f ( i , j , a i , b i , c i , d i , e i ) = ∑ f ( i − 1 , j − a i − b i − c i − d i − e i , a i − 1 , b i − 1 , c i − 1 , d i − 1 , e i − 1 ) f(i, j, a_i, b_i, c_i, d_i, e_i) = \sum_{}^{}f(i-1, j - a_i - b_i - c_i - d_i - e_i, a_{i-1}, b_{i-1}, c_{i-1}, d_{i-1}, e_{i-1}) f(i,j,ai,bi,ci,di,ei)=f(i1,jaibicidiei,ai1,bi1,ci1,di1,ei1)
当然上面的转移方程要满足规则限制,太过繁琐就略了(

这样的话一共5 * 5* 2^5 种状态,每次要从上一行的2^5的状态转移,每次要对a、b、c、d、e进行判断,一共计算5 * 5 * 2 ^ 5 * 2 ^ 5 * 5 = 640625次,时间复杂度大大降低

4.维度压缩

但是我们发现对于5*5的棋盘我们状态有7维,当棋盘增大,状态维度增加,太过于繁琐,有没有办法降维呢?

由于后五个维度只有0,1两种取值,所以可以将后五个维度看成二进制整数,换言之,一个位宽为5的二进制整数就能表示出后五个维度,二进制位第i位为1代表第i列放置国王,否则不放置

那么状态就压缩为了f[i][j][state],比如f[3][5][10010]就代表前3行放置5个国王,第2行的第1、4列进行放置的方案数


一、状压dp

1.认识状压dp

动态规划就是在N维空间上进行递推的过程,每个维度看作一个节点,且只有0(尚未访问)和1(已访问)两个值。那么dp的过程就是从**(0,0,0,0,……0)(1,1,1,1,……1)**的过程。

为了记录当前状态在每个维度上的坐标是0还是1,我们采用N位二进制数表示状态,即用[0, 2 ^ N - 1]的十进制整数存储节点的访问情况。为了记录最后经过的节点是哪一个,我们用节点编号作为附加信息,也记录在dp的状态中,这样我们就得到了由N和2^N大小两个维度构成的状态数组f[N][1 << N]。

常见的状压dp大致可以分为棋盘式(基于连通性)和集合型两类。


2.棋盘式(基于连通性)

棋盘式通常会给出n*m的矩阵,然后格子占用的规则,一般表现为同行的不同列间的限制以及和前面若干行的限制。我们可以用位长m的二进制整数来表示出一行各列的放置情况,然后根据规则初始化状态数组,进行状态转移。


2.1小国王
2.1.1题目链接

[P1896 SCOI2005] 互不侵犯 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

2.1.2思路分析

显然可以用n位二进制整数表示出一行的放置情况

在不考虑和其他行冲突的情况下,有效状态state满足((state << 1) & state) = 0,即无同行相邻国王

那么可以O(2^n)预处理出所有的同行有效状态,顺便计算每个状态的1的个数sum

然后定义状态数组,f[i][j][state]代表前i行放置j个国王且第i行状态为state的方案数

那么有状态转移方程:
f [ i ] [ j ] [ a ] = ∑ f [ i − 1 ] [ j − c ] [ b ] 其中 a & b = 0 , ( a < < 1 ) & b = 0 , ( a > > 1 ) & b = 0 , c = s u m ( a ) f[i][j][a] = \sum f[i-1][j-c][b]\\其中a\&b=0,(a<<1)\&b=0,(a>>1)\&b=0,c=sum(a) f[i][j][a]=f[i1][jc][b]其中a&b=0,(a<<1)&b=0,(a>>1)&b=0,c=sum(a)
显然有初始状态f[0][0][0] = 1,空棋盘方案为1

然后把转移方程翻译成代码即可,为了方便我们计算到n + 1行的状态,这样f[n + 1][k][0]即为答案

2.1.3AC代码
#include <iostream>
using namespace std;
#define int long long
const int N = 11, M = N * N + 5;
int f[N][M][1 << N], state[1 << N], sum[1 << N];
int n, k, tot = 0;
signed main()
{
    //freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> n >> k;
    for (int i = 0, ed = (1 << n); i < ed; i++)
        if (!(i & (i << 1)))
            state[tot] = i, sum[tot++] = __builtin_popcount(i);
    f[0][0][0] = 1;
    for (int i = 1; i <= n + 1; i++)
        for (int j = 0; j <= k; j++)
            for (int a = 0; a < tot; a++)
                for (int b = 0, c = sum[a]; b < tot; b++)
                {
                    if (j >= c && !(state[a] & state[b]) && !(state[a] & (state[b] << 1)) && !(state[a] & (state[b] >> 1)))
                        f[i][j][a] += f[i - 1][j - c][b];
                }
    cout << f[n + 1][k][0];
    return 0;
}
2.2玉米田
2.2.1题目链接

[P1879 USACO06NOV] Corn Fields G - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

2.2.2思路分析

在不考虑废弃玉米田和其他行限制的情况下,同行有效状态state满足:state << 1 & state = 0

那么同样的,我们预处理出同行的所有有效状态states

然后每一行的废弃玉米田都会对同行状态造成限制,我们开一个数组g[],g[i]也是一个n位二进制整数,第i行废弃玉米田格子对应位被置1,这样我们选择第i行状态的时候要满足state & g[i] = 0

定义状态数组f[][],f[i][j]代表前i行完成种植且第i行状态为j的最大方案数

有状态转移方程:
f [ i ] [ j ] = ∑ f [ i − 1 ] [ k ] , 其中 j & k = 0 且 j & g [ i ] = 0 f[i][j] = \sum f[i-1][k],其中j\&k=0且j\&g[i]=0 f[i][j]=f[i1][k],其中j&k=0j&g[i]=0
初始状态f[0][0] = 1,然后翻译转移方程为代码,同样计算到n + 1行,f[n+1][0]即为答案

2.2.3AC代码
#include <iostream>
using namespace std;
#define int long long
const int N = 14, M = N * N + 5, mod = 1e8;
int m, n, tot = 0;
int f[N][1 << N]{0}, states[1 << N], g[N];
signed main()
{
    freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> m >> n;
    for (int i = 1; i <= m; i++)
        for (int j = 0, t; j < n; j++)
            cin >> t, g[i] |= ((!t) << j);
    for (int i = 0, ed = (1 << n); i < ed; i++)
        if (!(i & (i << 1)))
            states[tot++] = i;
    f[0][0] = 1;
    for (int i = 1; i <= m + 1; i++)
        for (int j = 0; j < tot; j++)
            for (int k = 0; k < tot; k++)
                if (!(states[j] & g[i]) && !(states[j] & states[k]))
                    f[i][j] = (f[i][j] + f[i - 1][k]) % mod;
    cout << f[m + 1][0];
    return 0;
}
2.3炮兵阵地
2.3.1题目链接

[P2704 NOI2001] 炮兵阵地 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

2.3.2思路分析

和前两道不同的地方就是,每一行会受到相邻两行的限制,但是换汤不换药,我们按照之前的思路来即可

同样先预处理同行有效状态states,以及有效状态对应1的数目cnt

然后根据每行的地形,预处理出g[],g[i]为m位二进制整数,山地对应位置一

定义状态数组f[i][j][k],代表前i行布置完毕,第i - 1行状态为k,第i行状态为j

那么有状态转移方程:
f [ i ] [ j ] [ k ] = m a x ( f [ i − 1 ] [ k ] [ x ] ) + c n t [ j ] , j , k , x 两两相与为 0 , j & g [ i ] = k & g [ i − 1 ] = 0 f[i][j][k] = max(f[i-1][k][x])+cnt[j],j,k,x两两相与为0,j\&g[i]=k\&g[i-1]=0 f[i][j][k]=max(f[i1][k][x])+cnt[j]j,k,x两两相与为0j&g[i]=k&g[i1]=0
初始状态都是0,不用初始化

翻译递推为代码,处理到n+2行,这样答案就是f[n+2][0][0]

考虑节省空间,我们滚动数组优化,最终答案就是f[(n+2)&1][0][0]

2.3.3AC代码
#include <iostream>
using namespace std;
#define int long long
const int N = 103, M = 11, mod = 1e8;
int m, n, tot = 0;
int g[N], states[1 << M], cnt[1 << M], f[2][1 << M][1 << M];

signed main()
{
    //freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        for (int j = 0; j < m; j++)
        {
            char ch;
            cin >> ch;
            g[i] |= ((ch == 'H') << j);
        }
    for (int i = 0, ed = 1 << m; i < ed; i++)
        if ((i & (i >> 1)) || (i & (i >> 2)))
            continue;
        else
            states[tot] = i, cnt[tot++] = __builtin_popcount(i);

    for (int i = 1; i <= n + 2; i++)
        for (int j = 0; j < tot; j++)
            for (int k = 0; k < tot; k++)
                for (int x = 0; x < tot; x++)
                {
                    int a = states[j], b = states[k], c = states[x];
                    if ((a & b) || (b & c) || (a & c))
                        continue;
                    if ((a & g[i]) || (b & g[i - 1]))
                        continue;
                    f[i & 1][j][k] = max(f[(i - 1) & 1][k][x] + cnt[j], f[i & 1][j][k]);
                }
    cout << f[(n + 2) & 1][0][0];
    return 0;
}
2.4蒙德里安的梦想
2.4.1题目链接

291. 蒙德里安的梦想 - AcWing题库

2.4.2思路分析

先明确一点:横放方案数=竖放方案数=总方案数,因为对于一种方案只要横放确认了,那么剩下的都是竖放

和前面不同,我们考虑按列放置

如果格子被竖向覆盖或者横向终点覆盖,置0,被横向起点覆盖置1

如:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们定义状态f[i][j]代表放完前i列,第i列状态为j的方案数

那么f[i][j]可以由f[i - 1][]转移,初始有f[0][0] = 1,其它都是0

我们最终答案应该是f[m][0],因为最后一列无法作为横放起点

和前面不同,前面都是预处理同行合法状态,这里预处理合并两列合法状态,如:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

不难看出,两列合并即做或运算

而如果两列合并后有连续的奇数个0,说明非法

那么我们可以预处理出所有状态是否有连续奇数0的情况even,even[i] = 1说明没有

然后对于两列状态,显然要满足i & j = 0,如果不为0,说明有重合的横放

这样有状态转移方程
f [ i ] [ j ] = ∑ f [ i − 1 ] [ k ] , e v e n [ i & j ] = 1 且 i & j = 0 f[i][j] = \sum f[i - 1][k],even[i\&j]=1且i\&j=0 f[i][j]=f[i1][k]even[i&j]=1i&j=0
翻译成代码即可,最终输出f[m][0]
相对于前三题,这道题状态不好想

2.4.3AC代码
#include <iostream>
#include <iostream>
#include <algorithm>
#include <cstring>
#define int long long
using namespace std;
const int N = 12, M = 12;
int n, m;
int f[M][1 << N];
bool even[1 << N];
signed main()
{
    //freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    while (cin >> n >> m, n && m)
    {
        memset(f, 0, sizeof f), memset(even, 0, sizeof even);
        for (int i = 0, ed = (1 << n), cnt = 0; i < ed; i++)
        {
            cnt = 0, even[i] = 1;
            for (int j = 0; j < n; j++)
                if ((1 << j) & i)
                {
                    if (cnt & 1)
                    {
                        even[i] = 0;
                        break;
                    }
                }
                else
                    cnt++;
            if (cnt & 1)
                even[i] = 0;
        }
        f[0][0] = 1;
        for (int i = 1; i <= m; i++)
        {
            for (int j = 0, ed = (1 << n); j < ed; j++)
                for (int k = 0, ed = (1 << n); k < ed; k++)
                    if (!(j & k) && even[j | k])
                        f[i][j] += f[i - 1][k];
        }
        cout << f[m][0] << '\n';
    }
    return 0;
}

3.集合

集合型问题,一般根据每个元素选或不选,用二进制整数表示集合内元素选取状况来作为状态。根据集合内元素是否可重复使用可以分为重复覆盖问题和不可重复覆盖问题(当然这在舞蹈链中也有涉及)。

3.1 递归实现指数型枚举
3.1.1题目链接

92. 递归实现指数型枚举 - AcWing题库

3.1.2思路分析

每个数字都有选或不选两种情况,那么我们用n位二进制整数表示集合内元素选取情况即可

把[0, (1 << n) - 1]遍历一遍即可

3.1.3AC代码
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
bool vis[16]{0};
int n;
void dfs(int x, int state){
    if(x == n){
        for(int i = 0; i < n; i++)
            if(state & (1 << i))
                cout << i + 1 << ' ';
        cout << '\n';
        return;
    }
    dfs(x + 1, state), dfs(x + 1, state | (1 << x));
}
int main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> n;
    dfs(0, 0);
    return 0;
}

3.2最短Hamilton路径

3.2.1题目链接

91. 最短Hamilton路径 - AcWing题库

3.2.2思路分析

哈密顿路径问题是集合类状压dp中一个非常经典的问题,因为很多问题都能抽象成图模型,继而转化为哈密顿路径问题

哈密顿路径要求路径遍历所有点且只一次,显然是不可重复覆盖问题。

那么我们考虑用n位二进制整数表示当前路径包含的点

接下来就是设计状态,因为我们状压dp的状态一般要获取最后一步的位置,所以定义状态f[i][j]为从0出发当前路径状态为i且终点为j的最短距离

那么有状态转移方程:
f [ i ] [ j ] = m i n ( f [ i ] [ j ] , f [ a ] [ b ] + g [ b ] [ j ] ) ,其中 i > > j & 1 f[i][j] = min(f[i][j], f[a][b] + g[b][j]),其中i >> j \& 1 f[i][j]=min(f[i][j],f[a][b]+g[b][j]),其中i>>j&1
由于题目要求起点为0,所以初始状态f[1][0] = 0

写代码时有个优化就是因为要求从0出发所以有效状态满足i & 1

3.2.3AC代码
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define int long long
const int N = 20;
int n, g[N][N]{0}, f[1 << N][N];
signed main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> n;
    for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++)
            cin >> g[i][j];
    memset(f, 0x3f, sizeof f);
    f[1][0] = 0;

    for(int i = 0, ed = 1 << n; i < ed; i++)
        if(i & 1)
            for(int j = 0; j < n; j++)
                if(i >> j & 1)
                      for(int k = 0; k < n; k++)
                      if(i >> k & 1)
                            f[i][j] = min(f[i][j], f[i ^ (1 << j)][k] + g[k][j]);
    cout << f[(1 << n) - 1][n - 1];
    return 0;
}

3.3毕业旅行问题

3.3.1题目链接

731. 毕业旅行问题 - AcWing题库

3.3.2思路分析

和哈密顿路径问题几乎一样

我们计算出从0出发的哈密顿路径最短距离后,取所有点为终点的哈密顿路径长度加上终点到起点距离中最小的那个即可

3.3.3AC代码
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
//#define int long long
const int N = 20;
int n, f[1 << N][N], g[N][N];
signed main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> n;
    for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++)
            cin >> g[i][j];
    memset(f, 0x3f, sizeof f), f[1][0] = 0;
    for(int i = 0, ed = 1 << n; i < ed; i++)
        if(i & 1)
            for(int j = 0; j < n; j++)
                if(i >> j & 1)
                      for(int k = 0; k < n; k++)
                      if(i >> k & 1)
                            f[i][j] = min(f[i][j], f[i ^ (1 << j)][k] + g[k][j]);
    int ret = 0x3f3f3f3f;
    for(int i = 1; i < n; i++)
        ret = min(ret, f[(1 << n) - 1][i] + g[i][0]);
    cout << ret;
    return 0;
}

3.4 愤怒的小鸟

3.4.1题目链接

524. 愤怒的小鸟 - AcWing题库

3.4.2思路分析

状压dp的题很多时候是根据数据范围来推测用状压dp的,然后往那边靠

对于这个题目而言,每个坐标就是一个元素,抛物线方程中有两个未知数,所以任意两点确定一条抛物线,当然要去掉开口朝上和竖直线的情况

这样我们O(n^2)与处理出path[x][y],path[x][y]为n位二进制整数即代表xy所在抛物线穿过点的状态,处理方法就是确定曲线合法后遍历所有点判断该点是否在曲线上

然后定义状态f[i]代表选取集合状态为i时所用最少曲线数目

对于f[i],我们如果思考它可以由哪个状态转移而来的话太过困难

所以我们可以这样进行状态转移

对于状态i,从低到高枚举找到第一个未被包含的位x,然后有:
f [ i ∣ p a t h [ x ] [ j ] ] = m i n ( f [ i ∣ p a t h [ x ] [ j ] ] , f [ i ] + 1 ) f[i | path[x][j]] = min(f[i | path[x][j]], f[i] + 1) f[ipath[x][j]]=min(f[ipath[x][j]],f[i]+1)
代码实现时候,注意浮点数精度的处理

3.4.3AC代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define int long long
typedef pair<double, double> PDD;
const int N = 18, M = 1 << N, mod = 1e8;
const double eps = 1e-8;
int n, m;
int f[M], path[N][N];
PDD points[N];
int cmp(double x, double y)
{
    if (fabs(x - y) < eps)
        return 0;
    return x > y ? 1 : -1;
}
void solve()
{
    cin >> n >> m;
    for (int i = 0; i < n; i++)
        cin >> points[i].first >> points[i].second;
    memset(path, 0, sizeof path), memset(f, 0x3f, sizeof f), f[0] = 0;
    for (int i = 0; i < n; i++)
    {
        double x1 = points[i].first, y1 = points[i].second;
        path[i][i] = 1 << i;
        for (int j = 0; j < n; j++)
        {
            double x2 = points[j].first, y2 = points[j].second;
            if (!cmp(x1, x2))
                continue;
            double a = (y1 / x1 - y2 / x2) / (x1 - x2), b = y1 / x1 - a * x1;
            if (cmp(a, 0) >= 0)
                continue;
            int state = 0;
            for (int k = 0; k < n; k++)
            {
                double x = points[k].first, y = points[k].second;
                if (!cmp(a * x * x + b * x, y))
                    state |= (1 << k);
            }
            path[i][j] = state;
        }
    }

    for (int i = 0; i + 1 < 1 << n; i++)
    {
        int x = 0;
        for (int j = 0; j < n; j++)
        {
            if (!((1 << j) & i))
            {
                x = j;
                break;
            }
        }
        for (int j = 0; j < n; j++)
            f[i | path[x][j]] = min(f[i] + 1, f[i | path[x][j]]);
    }
    cout << f[(1 << n) - 1] << '\n';
}
signed main()
{
    //freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int _ = 1;
    cin >> _;
    while (_--)
        solve();
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/434948.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++ 快速排序快速选择OJ

目录 1、75. 颜色分类 2、912. 排序数组 3、 215. 数组中的第K个最大元素 4、LCR 159. 库存管理 III 1、75. 颜色分类 思路&#xff1a;利用快速排序思路&#xff0c;使用三指针分块进行优化。 [0,left]——小于key[left1,right-1]——等于key[right,nums.size()]——大于k…

抖店怎么做起来?2024新版操作逻辑,做项目要做一米宽万米深

我是王路飞。 不知不觉间&#xff0c;我已经在抖音电商这条赛道深耕走过了四年。 这四年里&#xff0c;我们有了自己的黑标品牌旗舰&#xff0c;有了自己的仓库配套周边&#xff0c;有了自己的模式体系人员&#xff0c;有了数不清的类目和产品操作经验。 收获着身后团队伙伴…

107. sort( )方法-排序列表元素(上)

107. sort( )方法-排序列表元素&#xff08;上&#xff09; 【目录】 文章目录 107. sort( )方法-排序列表元素&#xff08;上&#xff09;1. 作用2. 语法3. 数值列表排序4. key str.lower 排序时不区分字母大小写5. 如何理解区分大小写6. key len 按照元素的长度进行排序7.…

Objective-C blocks 概要

1.block的使用 1.1什么是block&#xff1f; Blocks是C语言的扩充功能&#xff1a;带有自动变量&#xff08;局部变量&#xff09;的匿名函数。 “带有自动变量”在Blocks中表现为“截取自动变量" “匿名函数”就是“不带名称的函数” 块&#xff0c;封装了函数调用及调用…

Tailscale中继服务derper使用docker-compose部署

docker启动 docker run --restart always \--name derper -p 12345:12345 -p 3478:3478/udp \-v /root/.acme.sh/xxxx/:/app/certs \-e DERP_CERT_MODEmanual \-e DERP_ADDR12345 \-e DERP_DOMAINxxxx \-d ghcr.io/yangchuansheng/derper:latestdocker-compose启动 version: …

STM32(18)I2C

串口通信缺点 一个设备就需要一个串口&#xff0c;单片机可能没有那么多串口外设 总线/非总线 主机&#xff1a;负责管理总线&#xff0c;可控制波特率、数据的通信方向 波特率&#xff1a;由主机产生波特率信号 数据的传输 每个从机都有7位地址&#xff0c;最后移位是读&a…

Android开发教程入门,那些被大厂优化的程序员们

Binder原理 1、概述 Android系统中&#xff0c;涉及到多进程间的通信底层都是依赖于Binder IPC机制。例如当进程A中的Activity要向进程B中的Service通信&#xff0c;这便需要依赖于Binder IPC。不仅于此&#xff0c;整个Android系统架构中&#xff0c;大量采用了Binder机制作…

计算机形式严峻,二本计算机研究生有没有必要读?

有一说一&#xff0c;不值得 现在的就业形式确实严峻&#xff0c;但是我觉得读一个二本的研究生并不能给你带来太大的价值&#xff0c;首先就是就业投简历的时候&#xff0c;面试官面对大量的简历&#xff0c;往往都是先按照学校筛选&#xff0c;985和211的放在一块&#xff0…

画图解题思路( ccf 201512-3)

分析 首先需要转换坐标系&#xff0c;可以将两个坐标系的点写出来&#xff0c;对比一下找规律 可以发现题目中的坐标(x, y)转变成数组坐标系为(n - y - 1, x); 然后再判断是画线还是填充 画线&#xff1a;先转换题目坐标&#xff0c;再遍历画线 填充&#xff1a;采用dfs

如何比较字形相同但编码不同的两个字

今天在做字符串比较时遇到个很新奇的问题&#xff0c;在此记录一下。 字符串比较最常用的方法就是equals方法&#xff0c;来看一下下面这个比较会返回什么结果呢&#xff1f; public static void main(String[] args) {{String s1 "⽹"; // 12153String s2 "…

HplusAdmin ASP.NET基本权限管理系统

HplusAdmin 介绍 一套ASP.NET WebForm(不用控件) hplusasp.netsqlserver 基本权限管理系统 http://hplus.baocaige.top 暂不开源&#xff0c;需要的滴滴或者留下邮箱&#xff01;&#xff01;&#xff01; 账号 普通账号 账号&#xff1a;user 密码&#xff1a;Aa123456普…

【笔记版】edgecore.yaml分析总结

1. 文件路径 /etc/kubeedge/config edgecore.yaml是该目录下唯一的文件 附上链接&#xff1a;edgecore.yaml 2. 文件生成方式 2.1 方式一 使用keadm安装部署的方式&#xff0c;执行完keadm join --cloudcore-ipportcloudcore监听的IP地址:端口&#xff08;默认为10002&…

1688商品详情数据采集,工程数据采集丨店铺数据采集丨商品详情数据采集

1688是中国的一个大型B2B电子商务平台&#xff0c;主要用于批发和采购各种商品。对于需要从1688上获取商品详情数据、工程数据或店铺数据的用户来说&#xff0c;可以采用以下几种常见的方法&#xff1a; 官方API接口&#xff1a;如果1688提供了官方的API接口&#xff0c;那么可…

项目中spring security与jwt.腾讯面试分享

写这篇文章是为了记录我面试pcg时平时没有留意或者钻研的地方。 面试是根据项目问的问题&#xff1a; 为什么采用jwt存储token&#xff1f; 我的项目是微服务项目&#xff0c;里面部署了资源服务和认证服务&#xff0c;这里选择jwt作为token一方面是可以存储用户的信息&#…

YOLOv7独家原创改进:特征融合涨点篇 | 广义高效层聚合网络(GELAN) | YOLOv9

💡💡💡本文独家改进:即结合用梯度路径规划(CSPNet)和(ELAN)设计了一种广义的高效层聚合网络(GELAN),高效结合YOLOv7,实现涨点。 将GELAN添加在backbone和head处,提供多个yaml改进方法 💡💡💡在多个私有数据集和公开数据集VisDrone2019、PASCAL VOC实现…

FPGA开发之libero元件实例化详细步骤

FPGA开发之libero模块实例化详细步骤 第一步&#xff0c;假设已经建立了两个文件&#xff0c;现在需要将这两个文件连接在一起&#xff0c;如下图所示&#xff1a; 第二步&#xff0c;建立一个SD顶层文件&#xff0c;操作如下&#xff1a; 得到结果如下&#xff1a; 点击OK得…

continue、break 和 return 的区别是什么?

continue、break和return同样是用于控制程序流程的关键字&#xff0c;它们有不同的作用和用法。 continue: 在Java中&#xff0c;continue语句同样通常用于循环结构&#xff08;如for循环、while循环&#xff09;。当程序执行到continue时&#xff0c;会立刻跳过当前循环中剩…

第三百八十六回

文章目录 概念介绍使用方法示例代码 我们在上一章回中介绍了Snackbar Widget相关的内容,本章回中将介绍TimePickerDialog Widget.闲话休提&#xff0c;让我们一起Talk Flutter吧。 概念介绍 我们在这里说的TimePickerDialog是一种弹出窗口&#xff0c;只不过窗口的内容固定显示…

K8s集群调度,亲和性,污点,容忍,排障

目录 1.调度约束 调度过程 指定调度节点 查看详细事件 获取标签帮助 修改成 nodeSelector 调度方式 2.亲和性 节点亲和性 Pod 亲和性 键值运算关系 硬策略 软策略 Pod亲和性与反亲和性 创建一个标签为 appmyapp01 的 Pod 使用 Pod 亲和性调度&#xff0c;创建多…

Win11桌面出现的这个图标“了解此图片”怎么关闭?

&#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是尘觉&#xff0c;希望我的文章可以帮助到大家&#xff0c;您的满意是我的动力&#x1f609; 在csdn获奖荣誉: &#x1f3c6;csdn城市之星2名 ⁣⁣⁣⁣ ⁣⁣⁣⁣ ⁣⁣⁣⁣ ⁣⁣⁣⁣ ⁣⁣⁣⁣ ⁣⁣⁣⁣ ⁣⁣⁣⁣ …