加载中...
【动态规划】背包问题
01背包问题每件物品只有一个,不断对第 i 个物品的状态做出决策,0 / 1 表示选 or 不选 题目在这里 题目有 N 件物品和一个容量是 V 的背包,每件物品只能使用一次。 第 i 件物品的体积是 v~i~ ,价值是 w~i~ 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。输出最大价值。 输入格式第一行两个整数N,V ,用空格隔开,分别表示物品数量和背包容积。接下来有 N 行,每行两个整数 v~i~,w~i~ ,用空格隔开,分别表示第 i 件物品的体积和价值。 输出格式输出一个整数,表示最大价值。 数据范围0 < N, V ≤ 10000 < v~i~, w~i~ ≤1000 输入样例4 51 22 43 44 5 输出样例8 解法二维首先定义 f[i][j]:只装前 i 个物品,背包容量为 j 时的最大价值 如果当前背包容量小于第 i 个物品体积,那么不能选第 i 个物品,则 f[i][j] = f[i - 1][j] 如果当前背包容量大于第 i 个物品体积,那么可以选第 i 个物品 选第 i 个物品时,f[i][j] = f[i - 1 ...
【动态规划】线性DP
数字三角形题目在这里 题目给定一个如下图所示的数字三角形,从顶部出发,在每一结点可以选择移动至其左下方的结点或移动至其右下方的结点,一直走到底层,要求找出一条路径,使路径上的数字的和最大。 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 输入格式 第一行包含整数 n,表示数字三角形的层数。 接下来 n 行,每行包含若干整数,其中第 i 行表示数字三角形第 i 层包含的整数。 输出格式 输出一个整数,表示最大的路径数字和。 数据范围 1 ≤ n ≤ 500,−10000 ≤ 三角形中的整数 ≤ 10000 输入样例573 88 1 0 2 7 4 44 5 2 6 5 输出样例30 解法每个点只可能从左上方点 or 右上方点走过来,所以在这 ...
【图论】判环问题
(未更新完,做到相关题再更新相关部分 无向图判断有无环并输出环上点例题:H. Mad City 利用变种拓扑排序,先把度为1的点存入队中,每次取出队头,遍历邻接点,再将该条边删除也就是将邻接点度数减一,直至队空,然后所有度数不为0的点都是在环上的点,输出即可 code for (int i = 0; i < n; i ++ ){ int x, y; cin >> x >> y; add(x, y), add(y, x); ind[x] ++, ind[y] ++ ;} function<void()> topsort = [&](){ queue<int> q; for (int i = 1; i <= n; i ++ ) if (ind[i] == 1) q.push(i); while (q.size()) { int u = q.front(); q.pop(); ...
【图论】有向图的强连通分量
理论基础什么是连通分量? 对于一个有向图,分量中任意两点u,v,必然可以从u走到v,且从v走到u,这样的分量叫做连通分量 如果一个连通分量加上任意一个点都不是连通分量了,就把它叫做 强连通分量 强连通分量的主要作用:将任意一个有向图转化成一个有向无环图即拓扑图(通过缩点的方式),缩点就是将所有连通分量缩成一个点 如何求强连通分量呢? 按照DFS的顺序搜,我们可以将边分为以下四类: 树枝边:(x, y),x是y的父结点 前向边:(x, y),x是y的祖先结点 后向边:(x, y),y是x的祖先结点 横叉边:往之前搜过的其他点搜 怎么判断一个点是否在强连通分量中? 情况一:存在后向边指向祖先结点 情况二:先走到横叉边,横叉边再走到祖先结点 (反正一定可以走到某个祖先) 基于这个想法—— ==Tarjan== 算法求强连通分量(SCC) 先给每个结点按照 DFS 访问顺序确定一个时间戳,时间戳越小说明越先访问到 dfn[u]:遍历到 u 的时间戳low[u]:从 u 开始走,能遍历到的最小时间戳id[i]:i 所在连通分量的编号 u是其所在强连通分量的最高点 <-> df ...
【图论】SPFA求负环
基础知识负环:环上权值之和是负数 求负环的常用方法 基于SPFA 统计每个点入队次数,如果某个点入队n次,则说明存在负环(完全等价于Bellman-Ford算法) 统计当前每个点的最短路中所包含的边数,如果某点的最短路包含的边数大于等于n,则说明存在负环 玄学结论:当所有点的入队次数超过2n时,就认为图中有很大肯存在负环 例题虫洞原题链接 农夫约翰在巡视他的众多农场时,发现了很多令人惊叹的虫洞。 虫洞非常奇特,它可以看作是一条 单向 路径,通过它可以使你回到过去的某个时刻(相对于你进入虫洞之前)。 农夫约翰的每个农场中包含 N 片田地,M 条路径(双向)以及 W 个虫洞。 现在农夫约翰希望能够从农场中的某片田地出发,经过一些路径和虫洞回到过去,并在他的出发时刻之前赶到他的出发地。 他希望能够看到出发之前的自己。 请你判断一下约翰能否做到这一点。 下面我们将给你提供约翰拥有的农场数量 F,以及每个农场的完整信息。 已知走过任何一条路径所花费的时间都不超过 10000 秒,任何虫洞将他带回的时间都不会超过 10000 秒。 输入格式 第一行包含整数 F,表示约翰共有 F 个农场。 对于 ...
【图论】最小生成树
基本方法Kruskal算法步骤与基本思路(1)初始化所有点,每个点单独在一个点集。把所有边按权重排序 (2)按边权重从小到大遍历每一条边,如果这条边的两个顶点不在同一个点集,就将它们加到同一点集,也就是选中这条边,以此类推 (3)如果最后加入同一个点集的点个数小于n个说明这个图不是连通图,无法生成最小生成树 Kruskal板子struct Edge{ int a, b, w; bool operator< (const Edge &W) const { return w < W.w; }}edges[M];int find(int x) // 判断x属于哪一个点集{ if (x != p[x]) p[x] = find(p[x]); return p[x];}int kruskal(){ sort(edges, edges + m); // 所有边按权重排序 for (int i = 1; i <= n; i ++ ) p[i] ...
【图论】Floyd
例题牛的旅行原题链接 农民John的农场里有很多牧区,有的路径连接一些特定的牧区。 一片所有连通的牧区称为一个牧场。 但是就目前而言,你能看到至少有两个牧区不连通。 现在,John想在农场里添加一条路径(注意,恰好一条)。 一个牧场的直径就是牧场中最远的两个牧区的距离(本题中所提到的所有距离指的都是最短的距离)。 考虑如下的两个牧场,每一个牧区都有自己的坐标: 图 1 是有 5 个牧区的牧场,牧区用“*”表示,路径用直线表示。 图 1 所示的牧场的直径大约是 12.07106, 最远的两个牧区是 A 和 E,它们之间的最短路径是 A-B-E。 图 2 是另一个牧场。 这两个牧场都在John的农场上。 John将会在两个牧场中各选一个牧区,然后用一条路径连起来,使得连通后这个新的更大的牧场有最小的直径。 注意,如果两条路径中途相交,我们不认为它们是连通的。 只有两条路径在同一个牧区相交,我们才认为它们是连通的。 现在请你编程找出一条连接两个不同牧场的路径,使得连上这条路径后,所有牧场(生成的新牧场和原有牧场)中直径最大的牧场的直径尽可能小。 输出这个直径最小可能值。 输入格式 第 1 行 ...
【图论】单源最短路
单源最短路的建图方式最短路问题可以分为以下两类: 边权非负——朴素Dijkstra、堆优化Dijkstra 有负权边——Bellman-Ford、SPFA 例题热浪原题链接 德克萨斯纯朴的民众们这个夏天正在遭受巨大的热浪!!! 他们的德克萨斯长角牛吃起来不错,可是它们并不是很擅长生产富含奶油的乳制品。 农夫John此时身先士卒地承担起向德克萨斯运送大量的营养冰凉的牛奶的重任,以减轻德克萨斯人忍受酷暑的痛苦。 John已经研究过可以把牛奶从威斯康星运送到德克萨斯州的路线。 这些路线包括起始点和终点一共有 T 个城镇,为了方便标号为 1 到 T。 除了起点和终点外的每个城镇都由 双向道路 连向至少两个其它的城镇。 每条道路有一个通过费用(包括油费,过路费等等)。 给定一个地图,包含 C 条直接连接 2 个城镇的道路。 每条道路由道路的起点 Rs,终点 Re 和花费 Ci 组成。 求从起始的城镇 Ts 到终点的城镇 Te 最小的总费用。 输入格式 第一行: 4 个由空格隔开的整数: T,C,Ts,Te; 第 2 到第 C+1 行: 第 i+1 行描述第 i 条道路,包含 3 个由空 ...
【图论】二分图
二分图,即可以将图中的所有顶点分层两个点集,每个点集内部没有边 判定图为二分图的充要条件:有向连通图不含奇数环 1、染色法可以解决二分图判断的问题 步骤与基本思路遍历图中每一个点,若该点未被染色,则遍历该点所相邻的点,相邻的点中未被染色的进行染色操作,已被染色的判断颜色是否合法,合法继续遍历,不合法退出 染色法板子bool flag = true;for (int i = 1; i <= n; i ++ ){ if (!color[i]) // 未被染色则开始遍历 { if (!dfs(i, 1)) { flag = false; break; } }}bool dfs(int u, int c){ color[u] = c; // 对该点进行染色 for (int i = h[u]; i != -1; i = ne[i]) { int j = e[i]; ...
【图论】最短路算法
1、Dijkstra算法不能处理边权为负的情况,复杂度O(nlogn) 步骤与基本思路(1)初始化距离数组dist[N],将其所有值赋为0x3f,并将起点1的dist初始化为0,存入优先队列heap中 (2)从所有未被遍历的点中找到与起点1的距离dist[i]最小的点,并将该点标记为已遍历 (3)利用刚刚遍历的这个点 i 更新所有 i 的出边所连的点与起点1的距离,更新后存入heap中 (4)重复操作(2)(3)直至heap空 Dijkstra板子int dijkstra() // 返回起点到终点的距离{ memset(dist, 0x3f, sizeof dist); dist[1] = 0; priority_queue<PII, vector<PII>, greater<PII>> heap; heap.push({0, 1}); // first为dist second为具体的点 while (heap.size()) { auto t = heap.t ...