首页 > 其他分享 >DP

DP

时间:2024-09-11 09:24:10浏览次数:1  
标签:int max DP now 1010 节点 dp

动态规划

  • 动态规划是一种通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。

三个条件:最优子结构,无后效性和子问题重叠。

最优子结构

  • 证明问题最优解的第一个组成部分是做出一个选择;
  • 对于一个给定问题,在其可能的第一步选择中,假定你已经知道哪种选择才会得到最优解。你现在并不关心这种选择具体是如何得到的,只是假定已经知道了这种选择;
  • 是否可以选择到当前最优

无后效性

  • 当前的最优子问题,不会再受到后续决策的影响。

子问题重叠

  • 可以通过储存答案的方式来避免重复求解相同的子问题,从而提升效率。;

基本方案

  • 将原问题划分为若干阶段,每个阶段对应若干个子问题,提取这些子问题的特征(称之为状态);
  • 寻找每一个状态的可能决策,或者说是各状态间的相互转移方式(用数学的语言描述就是状态转移方程)。
  • 按顺序求解每一个阶段的问题。

背包DP

01背包

通常问题为给你可以使用的最大容积m,所有物品n的价值w[i]和体积v[i],求最大价值

二维
  • 定义状态 dp[i][j]表示前i个物品使用了j的体积可以获得的最大价值
  • 状态转移 dp[i][j]=max(dp[iz][j],dp[i-1][j-v[i]]+w[i]);
  • 输出结果 dp[n][m]
#include<bits/stdc++.h>
using namespace std;
int w[1010],dp[1010][1010],sum[1010];
int m,t;
int main(){
	cin>>t>>m;
	for(int i=1;i<=m;i++){
		cin>>sum[i]>>w[i];
	}
	for(int i=1;i<=m;i++){
		for(int j=0;j<=t;j++){
			dp[i][j]=max(dp[i-1][j],dp[i][j]);
			if(j>=sum[i]){
				dp[i][j]=max(dp[i][j],dp[i-1][j-sum[i]]+w[i]);
			}
		}
	}
	cout<<dp[m][t];
	return 0;
}
一维
  • 定义状态 dp[j]表示使用体积为j的背包获得的最大价值
  • 状态转移 dp[j]=dp[j-v[i]]+w[i]
  • 输出结果 dp[m]
#include<bits/stdc++.h>
using namespace std;
int t,m;
int v[210],w[210];
int dp[2100];
signed main(){
	ios::sync_with_stdio(false);
	cin>>t>>m;
	for(int i=1;i<=m;i++)	cin>>v[i]>>w[i];
	for(int i=1;i<=m;i++){
		for(int j=t;j>=v[i];j--){
			dp[j]=max(dp[j-v[i]]+w[i],dp[j]); 
		}
	}
	cout<<dp[t];
	return 0;
}

注意:一维循环容积需要倒过来,这样才能保证只用了一次,其没有破坏上一次的更新

完全背包

与01背包类似,但没有每种物品只能使用一次的要求

二维
  • 定义状态 dp[i][j]表示前i个物品使用了j的体积可以获得的最大价值
  • 状态转移 dp[i][j]=max(dp[i-1][j],dp[i-1][j-v[i]]+w[i]);
  • 输出结果 dp[n][m]
#include<bits/stdc++.h>
using namespace std;
int w[1010],dp[1010][1010],sum[1010];
int m,t;
int main(){
	cin>>t>>m;
	for(int i=1;i<=m;i++){
		cin>>sum[i]>>w[i];
	}
	for(int i=1;i<=m;i++){
		for(int j=1;j<=t;j++){
			dp[i][j]=max(dp[i-1][j],dp[i][j]);
			if(j>=sum[i]){
				dp[i][j]=max(dp[i][j],dp[i][j-sum[i]]+w[i]);
			}
		}
	}
	cout<<dp[m][t];
	return 0;
}
一维
  • 定义状态 dp[j]表示使用了j的体积可以获得的最大价值
  • 状态转移 dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
  • 输出结果 dp[m]
#include<bits/stdc++.h>
using namespace std;
int w[1010],dp[1010],sum[1010];
int m,t;
int main(){
	cin>>t>>m;
	for(int i=1;i<=m;i++){
		cin>>sum[i]>>w[i];
	}
	for(int i=1;i<=m;i++){
		for(int j=sum[i];j<=t;j++){
			dp[j]=max(dp[j],dp[j-sum[i]]+w[i]);
		}
	}
	cout<<dp[t];
	return 0;
}

注意:枚举时要正着,想想为什么

多重背包

与01背包类似,但加上了最多一个可以装k[i]次

二维
  • 定义状态 dp[i][j]表示前i个物品使用了j的体积可以获得的最大价值
  • 状态转移 dp[i][j]=max(dp[i][j],dp[i-1][j-cv[i]]+cw[i]);
  • 输出结果 dp[n][m]
#include<bits/stdc++.h>
using namespace std;
int k[2010];
int w[1010],dp[1010][1010],sum[1010];
int m,t;
int main(){
	cin>>t>>m;
	for(int i=1;i<=m;i++){
		cin>>sum[i]>>w[i]>>k[i];
	}
	for(int i=1;i<=m;i++){
		for(int j=1;j<=t;j++){
			for(int c=0;c<=k[i]&&c*v[i]<=j;c++){
				dp[i][j]=max(dp[i][j],dp[i-1][j-c*sum[i]]+c*w[i]);	
			}
		}
	}
	cout<<dp[m][t];
	return 0;
}
一维
  • 定义状态 dp[j]表示使用了j的体积可以获得的最大价值
  • 状态转移 dp[j]=max(dp[j],dp[j-v[i]c]+w[i]c);
  • 输出结果 dp[m]
#include<bits/stdc++.h>
using namespace std;
int t,m;
int v[210],w[210];
int dp[2100];
int k[1010];
signed main(){
	ios::sync_with_stdio(false);
	cin>>t>>m;
	for(int i=1;i<=m;i++)	cin>>v[i]>>w[i]>>k[i];
	for(int i=1;i<=m;i++){
		for(int j=t;j>=v[i];j--){
			for(int c=0;c<=k[i]&&c*v[i]<=j;c++)
				dp[j]=max(dp[j-v[i]*c]+w[i]*c,dp[j]); 
		}
	}
	cout<<dp[t];
	return 0;
}

分组背包

与01背包类似

只需要加上k组中每组选一个最大的即可

#include<bits/stdc++.h>
using namespace std;
int n,m,maxn;
int a[10010],b[10001],dp[1100],c,t[1010],ans[1010][1100];
int main(){
	cin>>m>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i]>>b[i]>>c;
		maxn=max(maxn,c);
		ans[c][++t[c]]=i;
	}
	for(int i=1;i<=maxn;i++){
		for(int j=m;j>=0;j--){
			for(int k=1;k<=t[i];k++){
				if(j>=a[ans[i][k]]){
					dp[j]=max(dp[j],dp[j-a[ans[i][k]]]+b[ans[i][k]]);
				}
			}
		}
	}
	cout<<dp[m];
	return 0;
} 

LIS与LCS

最长上升子序列(LIS)

  • 给出一个序列,求最长上升子序列
    -设dp[i]表示前i个数的最长上升子序列是多长
    -dp[i]=max((dp[j]+1)*(a[j]<a[i]),dp[i])(j<i)
#include<bits/stdc++.h>
using namespace std;
long long n,a[5010],dp[5010];
int main(){
	cin>>n;
	for(int i=1;i<=n;i++)	cin>>a[i];
	dp[1]=1;
	for(int i=2;i<=n;i++){
		dp[i]=1;
		for(int j=1;j<=i-1;j++){
			dp[i]=max(dp[i],(dp[j]+1)*(a[j]<a[i]));
		}
	}
	long long maxn=-1e9;
	for(int i=1;i<=n;i++)
		maxn=max(maxn,dp[i]); 
	cout<<maxn;
	return 0;
}

但此方法只能通过O(N*N)的数据,我们还可以进行优化。

  • 通过维护一个单调递增的队列,来求最长上升子序列。
  • 期间通过二分的方法,来找到当前的值可以放在队列中的最优位置。
  • 最后答案就是队列的大小
#include<bits/stdc++.h>
using namespace std;
int n,a[20010];
int dp[20010];
int main(){
	cin>>n;
	int len=0;
	for(int i=1;i<=n;i++)	cin>>a[i];
	for(int i=1;i<=n;i++){
		if(a[i]>=dp[len]){
			dp[++len]=a[i];continue;
		}
		int tot=lower_bound(dp+1,dp+1+len,a[i])-dp;
		dp[tot]=a[i];
	}
	cout<<len; 
	return 0;
}

最长公共子序列(LCS)

  • 给出两个序列,求最长公共子序列
    -设dp[i][j]表示第一个序列前i个数与第二个序列的前j个匹配的最长公共子序列是多长
  • if(s1[i]==s2[j]) dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);
    -如果不满足那就继承上一次更新的。
  • if(s1[i]!=s2[j]) dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
#include<bits/stdc++.h>
using namespace std;
int n;
int dp[5010][5010];
string s1,s2;
int main(){
	cin>>n;
	s1=" "+s1;
	int len1=s1.size()-1;
	s2=" "+s2;
	int len2=s2.size()-1;
	for(int i=1;i<=len1;i++){
		for(int j=1;j<=len2;j++){
			if(s1[i]==s2[j]){
				dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);
			}
			else{
				dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
			}
		}
	}	
	cout<<dp[len1][len2];
	return 0;
}

区间DP

  • 顾名思义,区间DP,是把小区间转移到大区间,从而解决全局性问题。

一般有以下特点

  • 合并:将两个或多个部分进行整合,当然也可以反过来;
    -特征:能将问题分解为能两两合并的形式;
    -求解:对整个问题设最优值,枚举合并点,将问题分解为左右两个部分,最后合并两个部分的最优值得到原问题的最优值。

例题:

石子合并

  • 给定一排石子,合并代价为两堆的代价和,求一堆时最小代价
  • 设dp[l][r]表示l~r区间的最小代价;
  • dp[l][r]=dp[l][k]+dp[k+1][r]+pre[r]-pre[l-1]
  • 一个区间可以由两个区间的各自价值加上两堆本身的价值
#include<bits/stdc++.h>
using namespace std;
int n;
int dp[110][110];
int pre[110];
int a[110];
int main(){
	cin>>n;
	for(int i=1;i<=n;i++) for(int j=1;j<=n;j++)	dp[i][j]=INT_MAX;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		pre[i]=pre[i-1]+a[i];
		dp[i][i]=0;
	}
	for(int len=2;len<=n;len++){
		for(int l=1;l<=n-len+1;l++){
			int r=l+len-1; 	
			for(int k=l;k<r;k++){
				dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]+pre[r]-pre[l-1]);
			}
		}
	} 
	cout<<dp[1][n];
	return 0;
}

关路灯

  • 初始站在一个位置,给定每一个路灯的位置与每一秒的耗能,求怎样关路灯使耗能最少。
  • 由题意得每一个区间要最后到一个地方最优,这个位置一定是最左或最右边。
  • 所以设dp[l][r][0/1]为把区间l~r的区间全部关完站在(左/右)端点的最小值
  • 转移为 当前节点从一旁区间的(左/右)端点走到当前端点所有没有关的路灯的总耗能,可以用前缀和维护。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,c;
int a[210],dp[110][110][2];
int pre[210];
int d;
signed main(){
	cin>>n>>c;
	for(int i=1;i<=n;i++){
		cin>>a[i]>>d;
		pre[i]=pre[i-1]+d;
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			dp[i][j][0]=dp[i][j][1]=INT_MAX;
		}
	}
	dp[c][c][0]=dp[c][c][1]=0;
	for(int i=1;i<=n;i++){
		if(i!=c){
			dp[i][i][0]=dp[i][i][1]=abs(a[c]-a[i])*pre[n];
		}		
	}
	for(int len=2;len<=n;len++){
		for(int l=1;l<=n-len+1;l++){
			int r=l+len-1;
			dp[l][r][0]=min(dp[l][r][0],dp[l+1][r][0]+(a[l+1]-a[l])*(pre[n]-(pre[r]-pre[l])));
			dp[l][r][0]=min(dp[l][r][0],dp[l+1][r][1]+(a[r]-a[l])*(pre[n]-(pre[r]-pre[l])));
			dp[l][r][1]=min(dp[l][r][1],dp[l][r-1][0]+(a[r]-a[l])*(pre[n]-(pre[r-1]-pre[l-1])));
			dp[l][r][1]=min(dp[l][r][1],dp[l][r-1][1]+(a[r]-a[r-1])*(pre[n]-(pre[r-1]-pre[l-1])));
		}
	}
	cout<<min(dp[1][n][1],dp[1][n][0]);
	return 0;
}

树形DP与树上背包问题

树是什么?

  • n个点n-1条边且没有重边的图,两点之间的简单路径只有一条。

树的重心

  • 定义:以一个点作为根,使其子树的大小最小。

  • 设dp[i]为以i为根的最大字数大小,siz[i]表示子树大小

  • 由定义得:dp[u]=max(dp[u],siz[son[u]]);

  • 最后不要忘了dp[u]=max(dp[u],n-siz[u]);

void dfs(int now,int fa){
    siz[now]=1;
    dp[now]=0;
	for(int i=head[now];i;i=a[i].nxt){
		int to=a[i].to;
		if(to==fa)	continue;
		dfs(to,now);
        siz[now]+=siz[to];
		dp[now]=max(dp[now],siz[to]);	
		
	}	
	dp[now]=max(dp[now],n-siz[now]);
}

树的直径

  • 定义:树的最长两点的距离
  • 设dp[i][0/1]表示以i为父亲节点的[最大/次大](一点到父亲节点的长度)。
  • 为什么要这样设计?
  • 因为直径就是子树中的最远两点的距离,所以记录两个不同子树的最大值再+1,及从儿子节点跳到父亲节点。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,u,v;
struct node{
	int to,nxt;
}a[200010];
int head[200010],tot;
void add(int x,int y){
	a[++tot].to=y;
	a[tot].nxt=head[x];
	head[x]=tot;
}
int dp[100010][2];
int maxn;
void dfs(int now,int fa){
	for(int i=head[now];i;i=a[i].nxt){
		int to=a[i].to;
		if(to==fa)	continue;
		dfs(to,now);
		if(dp[now][0]<=dp[to][0]+1){
			dp[now][1]=dp[now][0];
			dp[now][0]=dp[to][0]+1;	
		}
		else{
			if(dp[now][1]<=dp[to][0]+1){
				dp[now][1]=dp[to][0]+1;
			}
		}
	}
	maxn=max(maxn,dp[now][0]+dp[now][1]);
}
signed main(){
	cin>>n;
	for(int i=1;i<n;i++){
		cin>>u>>v;
		add(u,v),add(v,u);
	}
	dfs(1,0);
	cout<<maxn;
	return 0;
}

树形DP

  • 从儿子到父亲(子信息合并)
  • 从父亲到儿子(深度累加,答案累加)

例题:

没有上司的舞会

  • 一个树形结构,一个点与父节点只能选择一个获得权值,问最大权值
  • 考虑DP,设DP[i][0/1]表示第i个节点不选以他为父节点的子树的最大权值。
  • DP[u][1]=DP[v][0]+w[u];
  • DP[u][0]=max(DP[v][1],DP[v][0]);
#include<bits/stdc++.h>
using namespace std;
int n,r[6010],l,k;
int fa[6010];
int dp[6010][2];
struct node{
	int to,nxt;
}a[12010];
int head[12010],tot;
void add(int x,int y){
	a[++tot].to=y;
	a[tot].nxt=head[x];
	head[x]=tot;
}
void dfs(int now,int f){
	fa[now]=f;
	dp[now][1]=r[now];
	for(int i=head[now];i;i=a[i].nxt){
		int to=a[i].to;
		if(to==f)	continue;
		dfs(to,now);
		dp[now][0]+=max(dp[to][0],dp[to][1]);
		dp[now][1]+=dp[to][0];
	}
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++)	cin>>r[i];
	for(int i=1;i<n;i++){
		int l,k;
		cin>>l>>k;
		add(l,k);
		add(k,l);
	} 
	dfs(1,0);
	cout<<max(dp[1][1],dp[1][0]);
	return 0;
}

树上背包

二叉苹果树

  • 给出一棵树,求断边后剩下的边的权值最大和
  • 考虑dp,设dp[i][k]表示i节点剩下k条边的最大权值
  • 转移,当前节点最大值是子节点用k条边最大值加上父节点用q-k-1条边,-1是因为父节点与子节点连边;
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,q;
int head[1010],tot;
struct node{
	int to,nxt,w;
}a[200];
void add(int x,int y,int w){
	a[++tot].to=y;
	a[tot].nxt=head[x];
	a[tot].w=w;
	head[x]=tot;
}
int dp[200][200];
int siz[200];
void dfs(int now,int fa){
	siz[now]=1;
	for(int i=head[now];i;i=a[i].nxt){
		int to=a[i].to;
		if(to==fa)	continue;
		dfs(to,now);
		siz[now]+=siz[to];
		for(int j=siz[now]-1;j>=1;j--){
			for(int k=0;k<j;k++){
				dp[now][j]=max(dp[now][j],dp[now][j-k-1]+dp[to][k]+a[i].w);
			}
		}
	}
}
signed main(){
	cin>>n>>q;
	for(int i=1;i<n;i++){
		int u,v,c;
		cin>>u>>v>>c;
		add(u,v,c),add(v,u,c);
	}
	dfs(1,-1);
	cout<<dp[1][q];
	return 0;
}

换根DP

例题:

STA-Station

  • 找到一个点作为根使深度总和最大
  • 朴素做法,做n遍dfs找到最大值
  • 正解:随便找一个点先做一遍dfs,找到以它为根节点的深度和。
  • 在第一次dfs时可以获得每个节点的的子树大小
  • 在第二遍dfs时可以得知父节点向子节点转移后,子节点最大应为父节点最大+父节点向子节点移的距离(即为1)乘以除子节点以外的节点数之和再减去向子节点移的距离*子节点的树的大小
#include<bits/stdc++.h>
#define int long long
int n,u,v;
using namespace std;
struct node{
	int to,nxt;
}a[2000010];
int f[1000100],g[1000010],sz[1000100],dep[1000010];
int tot,head[1000100];
void add(int x,int y){
	a[++tot].to=y;
	a[tot].nxt=head[x];
	head[x]=tot;
}
void dfs1(int now,int fa){
	sz[now]=1,dep[now]=dep[fa]+1;
	for(int i=head[now];i;i=a[i].nxt){
		int to=a[i].to;
		if(to==fa)	continue;
		dfs1(to,now);
		sz[now]+=sz[to];
	}
}
void dfs2(int now,int fa){	
	for(int i=head[now];i;i=a[i].nxt){
		int to=a[i].to;
		if(to==fa)	continue;	
		f[to]=f[now]+sz[1]-2*sz[to];
		dfs2(to,now);
	}
}
signed main(){
	cin>>n;
	for(int i=1;i<n;i++){
		cin>>u>>v;
		add(u,v);
		add(v,u);
	}
	dfs1(1,0);
	for(int i=1;i<=n;i++)
		f[1]+=dep[i];
	dfs2(1,0);
	int maxn=-1e9,id=0;
	for(int i=1;i<=n;i++){
		if(f[i]>maxn)
			maxn=f[i],id=i;
	}
	cout<<id;
	return 0;
} 

状压dp

  • 通过状态压缩的方式将每个情况枚举用2/3进制数来表示状态。
  • 一般适用于N<=20。
  • 一般把状态用二进制数相加。

例题

售货员的难题

  • 看到数据范围N<=20,发现可以状态压缩每个村庄去或不去。
  • 设dp[i][k]表示第i个村庄的状态
  • 可以知道一个村庄去某个村庄的状态可以由不去这个村庄再加上去这个村庄的路程
#include<bits/stdc++.h>
using namespace std;
int n,a[30][30],dp[21][1<<20|1];
int main(){
	cin>>n;
	memset(dp,0x3f,sizeof(dp));
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++)	cin>>a[i][j];
	}	
	dp[1][1]=0;
	for(int i=0;i<(1<<n);i++){ 
		for(int j=1;j<=n;j++){
			if(!(i&(1<<(j-1)))){
				for(int k=1;k<=n;k++){
					if(j==k)	continue;
					if((i&(1<<(k-1))))
						dp[j][i|(1<<(j-1))]=min(dp[j][i|(1<<(j-1))],dp[k][i]+a[k][j]);
				}
			}
		}
	}
	int ans=2e9;
	for(int i=2;i<=n;i++){
		ans=min(ans,dp[i][((1<<n)-1)]+a[i][1]);
	}
	cout<<ans;
	return 0; 
}

互不侵犯

  • 发现N很小,可以状压每一行的状态,发现可以由之前的状态到当前状态。
  • 考虑dp,dp[i][k][sum]表示当前到第i行状态为k,放了sum个的方案数的方案数
  • 当当前位置的上方,左上,右上或者左侧有棋子时无法放置;
  • 然后可以知道当前状态放了j个,可以由上一个状态放了sum[i]个转移
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN=9;
int n,m;
int sum[1<<MAXN|1];
int dp[MAXN+1][1<<MAXN|1][MAXN*10]; 
bool check(int x,int y){
	if((y&(y<<1))||(x&y)||(x&(y<<1))||(y&(x<<1)))	return 1;
	return 0;                                                                                                                                                                      
}
signed main(){
	cin>>n>>m;
	for(int i=0;i<(1<<n);i++){
		if(i&(i<<1))	continue;
		sum[i]=__builtin_popcount(i);
		dp[1][i][sum[i]]=1;
	} 
	for(int j=2;j<=n;j++){
		for(int i=0;i<(1<<n);i++){	
			if(i&(i<<1))	continue;
			for(int k=0;k<(1<<n);k++){
				if(check(i,k))	continue;
				for(int l=sum[i];l<=m;l++){
					dp[j][i][l]+=dp[j-1][k][l-sum[i]];
				}
			}
		}
	}
	int ans=0;
	for(int i=0;i<(1<<n);i++){
		ans+=dp[n][i][m];
	}
	cout<<ans;
	return 0;
}

标签:int,max,DP,now,1010,节点,dp
From: https://www.cnblogs.com/lmy333/p/18407674

相关文章

  • 搭建 WordPress 及常见问题与解决办法
    浪浪云活动链接:https://langlangy.cn/?i8afa52文章目录环境准备安装LAMP堆栈(Linux,Apache,MySQL,PHP)配置MySQL数据库安装WordPress配置WordPress常见问题及解决办法数据库连接错误白屏问题插件或主题冲突内存限制错误本文旨在介绍如何在服务器上搭......
  • 树形DP做题回顾(上)
    题目一 ​​​​Problem-2196大致意思就是求每个点为根的最大深度;对于这个问题,很快速的我们可以想到跑两次dfs,第一次预处理出以u为根的子树的第一,二深的深度,第二次dfs进行树形dp,从u->v时推出v的最大深度,用up[v]来存储;代码如下:注意分走到第一大和第二大的路径上的决策,以......
  • 虚树+树形dp
    虚树实际上是一颗浓缩子树;使用虚树的题目大部分具有查询的点有限,同时虚树构建的信息符合规则;做虚树的题目:步骤为先想出原树的暴力求解做法,然后构建虚树同时向其中添加有用信息(比如边权);虚树的构建过程:虚树的构建大致有两种,但是两种方式都与dfs序有关;首先解释为什么与dfs序有......
  • 线性dp:LeetCode122.买卖股票的最佳时机ll
    买卖股票本文所讲解的内容与LeetCode122.买卖股票的最佳时机ll,这道题题意相同,阅读完本文后可以自行挑战一下力扣链接题目叙述:给定一个长度为N的数组,数组中的第i个数字表示一个给定股票在第i天的价格。设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交......
  • Wordpress采集发布插件-免费下载
    推荐一款可以自动采集文章数据,并发布到Wordpress网站的Wordpress采集发布插件,支持对接简数采集器,火车头采集器,八爪鱼采集器,后羿采集器等大多数网页文章数据采集软件。Wordpress采集发布插件使用方法如下:1. 下载并安装Wordpress采集发布插件1.1 Wordpress采集发布插件免费下载......
  • DP
    动态规划动态规划是一种通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。三个条件:最优子结构,无后效性和子问题重叠。最优子结构证明问题最优解的第一个组成部分是做出一个选择;对于一个给定问题,在其可能的第一步选择中,假定你已经知道哪种选择才会得到最优解......
  • [DPDK] dumpcap报错EAL init failed: is primary process running?解决办法
    [DPDK]dumpcap报错EALinitfailed:isprimaryprocessrunning?解决办法问题我写了一个DPDK程序,现在想要用DPDK自带的dpdk-dumpcap工具来抓包测试。根据官网描述,我们需要先启动我们的程序为主进程,然后启动dpdk-dumpcap为副进程。但是我直接运行dpdk-dumpcap,显示如下错误:注:......
  • TCP和UDP对比
    TCP和UDP对比TCP(TransmissionControlProtocol,传输控制协议)和UDP(UserDatagramProtocol,用户数据报协议)是两种常用的网络传输层协议,它们在网络通信中扮演着重要的角色。以下是它们的主要区别:连接性:TCP:TCP是一种面向连接的协议,在数据传输之前需要建立一个连接(三次握手),数据......
  • TCP和UDP
    TCP(TransmissionControlProtocol,传输控制协议)和UDP(UserDatagramProtocol,用户数据报协议)是两种常用的网络传输层协议,它们在网络通信中扮演着重要的角色。以下是它们的主要区别:连接性:TCP:是一种面向连接的协议。在数据传输开始之前,必须建立一个连接,通过三次握手过程来确保......
  • NPDP和PMP有啥区别?其实就这个3点
    1、发证机构不同PMP是由项目管理协会PMI发起,严格评估项目管理人员知识技能是否具有高品质的资格认证考试。1999年,中国国际人才交流基金会将项目管理协会制定的《项目管理知识体系指南》和“项目管理专业人士职业资格认证”引入中国。NPDP是由美国产品开发与管理协会PDMA......