当前位置: 首页 > news >正文

算法训练1

01背包问题

背包状态方程----动态规划

二维dp

使用 f[i][j] = max(f[i-1][j] ,f[i-1][j - w[i]] + v[i]);

 伪代码:

int dp[100][100];
void test6() {int n;  //装备数量int m;  //背包容量int v[105], w[105]; //前面空间,后面价值for (int i = 1; i <= n; i++) {for (int j = m; j >= 0; j--) {if (j >= v[i]) {dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - v[i]] + w[i]);}else {dp[i][j] = dp[i - 1][j];}}}
}

 其中,dp中的横坐标i代表的是第i个装备,纵坐标 j 为背包容量,由于这里dp一直记录的是最大的,所以可以优化为一维dp

 同理的一道题:

 使用一维dp,注意的是:进行更新 f[ ]时,要从后面开始更新,这样可以使用的f[j - v[i]] 全是上次草药的值,如果从小往大进行更新,会导致后面更新,装两次一样的草药。导致错误。

void test3() {int timeAll, num;scanf("%d%d", &timeAll, &num);int v[105],w[105];int f[1005];for (int i = 1; i <= num; i++) {scanf("%d %d", &v[i], &w[i]);}for (int i = 0; i <= timeAll; i++) {f[i] = 0;}for (int i = 1; i <= num; i++) {for (int j = timeAll; j >= 0; j--) {if (j >= v[i]) {f[j] = max(f[j], f[j - v[i]] + w[i]);}else {f[j] = f[j];}}}printf("%d", f[timeAll]);
}

桶排序+暴力处理

 这里就不断处理最大值,最大湿度衣服进行烘干,然后暴力执行。

//堆排序
int f[500005];
void test5() {int n, a, b;scanf("%d%d%d", &n, &a, &b);int max = 0, sum = 0,time = 0;for (int i = 1; i <= n; i++) {int k;scanf("%d", &k);f[k]++;if (k > max) {max = k;}}while (1) {if (max <= sum) {break;}f[max]--;if (max > b) {f[max - b] += 1;}while(f[max] == 0) {max--;}sum += a;time += 1;}printf("%d", time);}

二分答案:

题解 P2678 【跳石头】 - 洛谷专栏 (luogu.com.cn)icon-default.png?t=N7T8https://www.luogu.com.cn/article/08mxthsv

运用二分答案,进行枚举判断答案是否正确

比如:

 使用check函数检查答案是否正确,运用二分答案:两个要素

单调性,有界性。答案可以枚举出来

#define _CRT_SECURE_NO_WARNINGS 
#include<cstdio> 
#include<cstring>
#include<iostream>
#include<algorithm>using namespace std;
int H[1000005];
int N, M;
bool check2(int l) {int count = 0;for (int i = 1; i <= N; i++) {if (H[i] > l) {count += H[i] - l;if (count >= M) {return true;}}}return false;
}int max(int a, int b) {return a > b ? a : b;
}void test8() {scanf("%d%d", &N, &M);for (int i = 1; i <= N; i++) {scanf("%d", &H[i]);}sort(H + 1, H + 1 + N);int left = 1, right = H[N], ans = 0;while (left <= right) {int mid = (left + right) / 2;if (check2(mid)) {ans = max(ans, mid);left = mid + 1;}else {right = mid - 1;}}cout << ans;}
int main() {test8();
}

 还有这题:P1824 进击的奶牛 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

 同理:使用二分答案,解决


 

#define _CRT_SECURE_NO_WARNINGS 
#include<cstdio> 
#include<cstring>
#include<iostream>
#include<algorithm>
int V[200005];
int N, C, H;
using namespace std;
int check(int k) {int last = V[1], count = 0;for (int i = 2; i <= N; i++) {if (V[i] - last < k) {count++;if (H < count)return 1;}else {last = V[i];}}return 0;
}int max(int a, int b) {return a > b ? a : b;
}void swap(int* a, int* b) {int t = *a;*a = *b;*b = t;
}void test7() {scanf("%d %d", &N, &C);for (int i = 1; i <= N; i++) {scanf("%d", &V[i]);}H = N - C;sort(V+1,V+N+1);int left = 1, right = V[N], ans = 0;while (left <= right) {int mid = (left + right) / 2;if (check(mid) == 0) {ans = max(mid, ans);left = mid + 1;}else {right = mid - 1;}}printf("%d", ans);}
int main() {test7();
}

并查集

比如:

P3367 【模板】并查集 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

找祖先,就一直找到最初的组件,判断是否相等,如果相等,就说明这两个是在同一个集合中。

int find(int x) {while (x != f[x]) {x = f[x];}return x;
}//路径压缩,循环实现
int find(int x){while (x != f[x]){f[x] = f[f[x]];x = f[x]}return x;
}//路径压缩,递归实现
int find(int x){if(x == f[x])return x;return f[x] = find[f[x]];
}

 路径压缩后会可以使查询祖先时,快不少。

并查集还有一个重要的出来查询之外,还有合并了

这里可以直接把一个元素的祖先赋值给一个元素的祖先

void merge(int a,int b){int a1 = find(a);int a2 = find(b);f[a1] = a2;
}

 

#define _CRT_SECURE_NO_WARNINGS 
#include<cstdio> 
#include<cstring>
#include<iostream>
#include<algorithm>using namespace std;
int N, M;
int f[10005];
void init() {for (int i = 1; i <= N; i++) {f[i] = i;}
}int find(int x) {while (x != f[x]) {f[x] = f[f[x]];x = f[x];}return x;
}void test8() {cin >> N >> M;init();for (int i = 1; i <= M; i++) {int z, x, y;cin >> z >> x >> y;if (z == 1) {f[find(x)] = find(y);}else if (z == 2) {if (find(x) == find(y)) {cout << "Y\n";}else {cout << "N\n";}}}}
int main() {test8();
}

最小生成树

算法:prim,kruskal算法

主要学习了kruskal算法

运用到了并查集。P3366 【模板】最小生成树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

顺便学习了c++中sort函数,自定义排序方式,

图中的边权值,进行排序。

kruskal:先找出最小没有连接的边,然后判断如果连接后有没有回路,如果有回路,就舍弃这条边,没有就把这条边加入,然后再进行判断下一条边。

P1195 口袋的天空 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

类似的,这个是需要把n个点构造成k棵最小生成树,所以只要加入的边等于n-k就行了

附上代码

#define _CRT_SECURE_NO_WARNINGS 
#include<cstdio> 
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int N, M, K;
int f[1005];struct edge {int v, u, w;
}edges[10005];int find(int x) {while (f[x] != x) {f[x] = f[f[x]];x = f[x];}return x;
}
bool cmp(edge a, edge b) {return a.w < b.w;
}void kruskal() {int ans = 0, cnt = 0;sort(edges + 1, edges + M + 1, cmp);for (int i = 1; i <= M; i++) {int a1 = find(edges[i].u);int a2 = find(edges[i].v);if (a1 == a2) {continue;}ans += edges[i].w;f[a1] = a2;    //连接两个顶点cnt++;if (cnt == N - K) {cout << ans;return;}}cout << "No Answer";
}void test() {cin >> N >> M >> K;for (int i = 1; i <= N; i++) {f[i] = i;}for (int i = 1; i <= M; i++) {cin >> edges[i].u >> edges[i].v >> edges[i].w;}kruskal();
}
int main() {test();
}

 

最短路径

dijkstra算法+链式前向星存边,

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
#include <algorithm>
#include<cstring>
#define inf 2147483647
using namespace std;
long long dis[10005];
bool vis[10005];
int head[10005];
int n, m, s,cnt = 0;
//在这里head数组储存i点的一条边的编号,edge中的next表示的是起点相同的边的编号,
//可以从加边那里深刻理解
//链式前向星存边
struct edge {int next;int to;int val;
}edges[500005];void dijkstra() {dis[s] = 0;int cur = s;while (!vis[cur]) {vis[cur] = true;for (int i = head[cur]; i != 0; i = edges[i].next) {if (!vis[edges[i].to] && dis[edges[i].to] > dis[cur] + edges[i].val) {dis[edges[i].to] = dis[cur] + edges[i].val;}}int min = inf;for (int i = 1; i <= n; i++) {if (!vis[i] && min > dis[i]) {min = dis[i];cur = i;}}}for (int i = 1; i <= n; i++) {cout << dis[i] <<" ";}
}//加边
void add(int a,int b,int c) {edges[++cnt].next = head[a];edges[cnt].to = b;edges[cnt].val = c;head[a] = cnt;            //记录编号
}void test() {cin >> n >> m >> s;for (int i = 1; i <= m; i++) {int a, b, c;cin >> a >> b >> c;add(a, b, c);}for (int i = 1; i <= n; i++) {dis[i] = inf;}dijkstra();
}int main() {test();
}

训练总结:昨天晚上加今天一天完成了这所有的训练,确实收获不少。

靠思维,暴力解决:A,,K,L

动态规划还是不太熟练, B

二分答案,能够理解。  C,D,E,F

 并查集:G,H

最小生成树:H,I

最短路径:J

思路有个大概,但是完全自己想出来,还是有点难度

 

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 2024-08-01 QML开发小技巧二
  • 华为OD应聘最全流程!!!
  • python初涉
  • memos content too long
  • 玩机进阶教程-----手机恢复出厂 误删除照片视频 误刷机后 几种数据恢复操作步骤解析【一】
  • 【通俗理解】马尔科夫毯:信息屏障与状态独立性的守护者
  • 基于地理面矢量的虚拟围栏
  • 深入 go interface 底层原理
  • 多模态模型BLIP2学习笔记
  • apache2和httpd web服务器
  • JavaScript 和 HTML5 Canvas实现图像绘制与处理
  • Java:多线程(进程线程、线程状态、创建线程、线程操作)
  • 【 问题 】 AT32 F413CB 设置SRAM大小为64KB 导致Flash后64KB代码执行变慢 解决办法
  • 搞懂数据结构与Java实现
  • 维度的精减:sklearn中分层特征降维技术全解析
  • [微信小程序] 使用ES6特性Class后出现编译异常
  • 【407天】跃迁之路——程序员高效学习方法论探索系列(实验阶段164-2018.03.19)...
  • 【node学习】协程
  • Date型的使用
  • JS笔记四:作用域、变量(函数)提升
  • vue2.0一起在懵逼的海洋里越陷越深(四)
  • webgl (原生)基础入门指南【一】
  • 大数据与云计算学习:数据分析(二)
  • 对超线程几个不同角度的解释
  • 力扣(LeetCode)22
  • 深度学习入门:10门免费线上课程推荐
  • 线性表及其算法(java实现)
  • 消息队列系列二(IOT中消息队列的应用)
  • 与 ConTeXt MkIV 官方文档的接驳
  • ionic入门之数据绑定显示-1
  • ​​​​​​​ubuntu16.04 fastreid训练过程
  • # 移动硬盘误操作制作为启动盘数据恢复问题
  • (3)(3.5) 遥测无线电区域条例
  • (3)Dubbo启动时qos-server can not bind localhost22222错误解决
  • (8)STL算法之替换
  • (Charles)如何抓取手机http的报文
  • (day 2)JavaScript学习笔记(基础之变量、常量和注释)
  • (webRTC、RecordRTC):navigator.mediaDevices undefined
  • (附源码)小程序儿童艺术培训机构教育管理小程序 毕业设计 201740
  • (佳作)两轮平衡小车(原理图、PCB、程序源码、BOM等)
  • (论文阅读22/100)Learning a Deep Compact Image Representation for Visual Tracking
  • (十三)Maven插件解析运行机制
  • (一)基于IDEA的JAVA基础12
  • (译) 函数式 JS #1:简介
  • (译)计算距离、方位和更多经纬度之间的点
  • (原創) 人會胖會瘦,都是自我要求的結果 (日記)
  • (转) ns2/nam与nam实现相关的文件
  • (转)h264中avc和flv数据的解析
  • (转)iOS字体
  • ***通过什么方式***网吧
  • .bat文件调用java类的main方法
  • .Net 6.0--通用帮助类--FileHelper
  • .net core 6 使用注解自动注入实例,无需构造注入 autowrite4net
  • .net core 客户端缓存、服务器端响应缓存、服务器内存缓存
  • .NET 给NuGet包添加Readme