【第十四届蓝桥杯考前速成】必考知识点及代码模板总结,看完至少多拿50分

简介: 四、简单图论1、单源最短路径2、多源最短路3、最小生成树五、动态规划1、0-1背包2、完全背包3、多重背包4、线性DP总结

四、简单图论

1、单源最短路径

Dijkstra算法:求解边权均为正的单源最短路。

朴素版本:适用于稠密图(边数和点数平方一个数量级)


代码模板

int n;      //点数

int g[N][N];    //邻接矩阵存储图

int dist[N];    //存储每个点到1号点的最短距离

bool st[N];    //存储每个点的最短路是否已经确定

int dijkstra(){

memset(dist,0x3f,sizeof dist);

dist[1]=0;

for(int i=0;i<n;i++){    //迭代n次

 int t=-1;

 for(int j=1;j<=n;j++){   //寻找距离最小的点

  if(!st[j]&&(t==-1||dist[t]>dist[j])) t=j;

  }

  st[t]=true;      //标记为已确定

  for(int j=1;j<=n;j++) dist[j]=min(dist[j],dist[t]+g[t][j]);   //用距离最小的点来更新其他点距离1号点的距离

}

if(dist[n]==0x3f3f3f3f) return -3;    //最短路不存在

else return dist[n];                  //存在直接返回

}


选看:

堆优化Dijkstra算法:适用于稀疏图(边数和点数一个数量级)可以参考我的该篇博客


Spfa算法:求解存在负权边的最短路。


代码模板

int n,m;     //n表示点数,m表示边数

int h[N],e[M],ne[M],w[M],idx;   //邻接表存储图

int dist[N];       //存储每个点到1号点的最短距离

bool st[N];       //存储每个点是否已经在队列中

//邻接表加边

void add(int a,int b,int c){

e[idx]=b;

w[idx]=c;

ne[idx]=h[a];

h[a]=idx++;

}

int spfa(){

memset(dist,0x3f,sizeof dist);

queue<int> q;

dist[1]=0;

st[1]=true;

q.push(1);

while(!q.empty()){

 int t=q.front();

 q.pop();

 st[t]=false;

 for(int i=h[t];i!=-1;i=ne[i]){

  int j=e[i];

  if(dist[j]>dist[t]+w[i]){

   dist[j]=dist[t]+w[i];

   if(!st[j]){

    st[j]=true;

    q.push(j);

   }

  }

 }

}

if(dist[n]==0x3f3f3f3f) return -3;

else return dist[n];

}


参考例题:这里


2、多源最短路

注:若时间紧迫,优先记忆Floyd算法,也可解决单源最短路问题,只不过时间复杂度较高,可以用其获得部分分数。

Floyd算法:求解多源最短路。

代码模板

int n;       //点数

int d[N][N];       //邻接矩阵存储图,算法结束后d[i][j]存储i、j之间的最短路径长度

for(int i=1;i<=n;i++){

for(int j=1;j<=n;j++){

 if(i==j) d[i][j]=0;

 else d[i][j]=0x3f3f3f3f;

}

}

void floyd(){

for(int k=1;k<=n;k++){

 for(int i=1;i<=n;i++){

  for(int j=1;j<=n;j++){

   d[i][j]=min(d[i][j],d[i][k]+d[k][j]);

  }

 }

}

}

//注意,若图中存在负权边,所以1号点无法到n号点,d[1][n]也可能被更新也可能则d[i][j]若大于0x3f3f3f3f/2即可认为最短路不存在



参考例题:这里


3、最小生成树


Prim算法:

代码模板

int n;      //点数

int dist[N];  //存储点到当前最小生成树的距离

int g[N][N];  //邻接矩阵存储每条边

bool st[N];   //存储每个点是否已经在生成树中

int prim(){

memset(dist,0x3f,sizeof dist);

int res=0;     //存储最小生成树边权重之和

for(int i=0;i<n;i++){

 int t=-1;

 for(int j=1;j<=n;j++){    //寻找距离当前生成树最小的点

  if(!st[j]&&(t==-1||dist[t]>dist[j])) t=j;

 }

 if(i&&dist[t]==0x3f3f3f3f3) return 0x3f3f3f3f;    //如果距离最小的点的距离仍然是正无穷说明无最小生成树

 if(i) res+=dist[t];

 for(int j=1;j<=n;j++) dist[j]=min(dist[j],g[t][j]);

 st[t]=true;

}

return res;    //返回最小生成树边权重之和即可

}


Kruakal算法:

代码模板


int p[N];            //并查集父结点数组

int find(int x){     //并查集find操作

if(p[x]!=x) p[x]=find(p[x]);

return p[x];

}

struct Edge{      //存储每条边

int a,b,w;

}edges[M];

bool cmp(Edge A,Edge B){    //手写cmp,使sort能为结构体排序

return A.w<B.w;

}

int kruskal(){

for(int i=1;i<=n;i++) p[i]=i;        //初始化并查集

sort(edges,edges+m,cmp);             //按边权从小到大排序

int res=0,cnt=0;                    //res记录最小生成树边权之和,cnt记录当前最小生成树种的边数

for(int i=0;i<m;i++){

 int a=edges[i].a,b=edges[i].b,w=edges[i].w;

 if(find(a)!=find(b)){           //最小边权的起点和终点a,b不在一个连通块则合并他们

  p[find(b)]=find(a);

  res+=w;

  cnt++;

 }

}

if(cnt<n-1) return 0x3f3f3f3f;      //n个点,最小生成树的边应为n-1条,少于n-1说明没有最小生成树

else return res;

}


参考例题:这里


五、动态规划

1、0-1背包

0-1背包问题:每件物品只有一个。

代码模板

int dp[N];        //存储每个状态的最大价值

int v[N],w[N];    //v[]存储每个物品的体积,w[]存储每个物品的价值

int n,m;          //n为物品数,m为背包容积

for(int i=1;i<=n;i++){    //枚举每个物品

for(int j=m;j>=v[i];j--){   //逆序枚举背包体积

 dp[j]=max(dp[j],dp[j-v[i]]+w[i]);

}

}


具体参考这里


2、完全背包

完全背包问题:每种物品有无限个。

代码模板

int dp[N];        //存储每个状态的最大价值

int v[N],w[N];    //v[]存储每个物品的体积,w[]存储每个物品的价值

int n,m;          //n为物品数,m为背包容积

for(int i=1;i<=n;i++){    //枚举每个物品

for(int j=v[i];j<=m;j++){   //正序枚举背包体积

 dp[j]=max(dp[j],dp[j-v[i]]+w[i]);

}

}


3、多重背包

多重背包问题:每种物品有不同数量。

代码模板

int dp[N];        //存储每个状态的最大价值

int v[N],w[N],s[N];    //v[]存储每个物品的体积,w[]存储每个物品的价值,s[]存储每个物品的最大数量

int n,m;          //n为物品数,m为背包容积

for(int i=1;i<=n;i++){    //枚举每个物品

for(int j=m;j>=v[i];j--){   //逆序枚举背包体积

 for(int k=0;k<=s[i]&&k*v[i]<=j;k++){

  dp[j]=max(dp[j],dp[j-k*v[i]]+k*w[i]);

 }

}

}


参考例题:这里


4、线性DP

DP没有固定模板,建议复习一下最长上升子序列和最长公共子序列问题的解题思想。


总结

以上内容均为比较基础的内容,如果学有余力,可以多拓展一些,真正的强者不应止步于此,我去写周赛题解了,再见。

最后希望我们都能取得自己心仪的成绩,我们一起加油,奥利给!


目录
相关文章
|
1月前
蓝桥杯真题代码记录(保险箱
蓝桥杯真题代码记录(保险箱
20 1
蓝桥杯真题代码记录(保险箱
|
1月前
|
网络安全 数据安全/隐私保护 计算机视觉
2024蓝桥杯网络安全-图片隐写-缺失的数据(0基础也能学会-含代码解释)
2024蓝桥杯网络安全-图片隐写-缺失的数据(0基础也能学会-含代码解释)
|
1月前
|
传感器
蓝桥杯真题代码记录(管道
蓝桥杯真题代码记录(管道
19 2
|
1月前
蓝桥杯真题代码记录(直线
蓝桥杯真题代码记录(直线
16 0
|
1月前
蓝桥杯真题代码记录(卡片
蓝桥杯真题代码记录(卡片
20 0
|
1月前
蓝桥杯真题代码记录(最优清零方案
蓝桥杯真题代码记录(最优清零方案
13 0
|
1月前
蓝桥杯真题代码记录(蜂巢
蓝桥杯真题代码记录(蜂巢
13 0
|
1月前
蓝桥杯真题代码记录(数位排序
蓝桥杯真题代码记录(数位排序
16 0
|
1月前
蓝桥杯真题代码记录(纸张尺寸
蓝桥杯真题代码记录(纸张尺寸
13 0