dfs

dfs需要剪枝

我们两清 提交于 2020-03-10 05:23:42
问题 G: 优美的排列 题目描述 假设有从 1 到 N 的 N 个整数,如果从这 N 个数字中成功构造出一个数组,使得数组的第 i 位 (1 <= i <= N) 满足如下两个条件中的一个,我们就称这个数组为一个优美的排列。条件: I. 第 i 位的数字能被 i 整除 II. i 能被第 i 位上的数字整除 现在输入一个整数 N,请问可以构造多少个优美的排列? 输入 输入样例由多组测试数据组成。每组测试数据第一行输入一个正整数 N ( 1 <= N <= 15 ) 输出 输出可以构造的优美的排列的数量 样例输入 2 样例输出 2 提示 参照输入样例: 第 1 个优美的排列是 [1, 2]: 第 1 个位置(i=1)上的数字是1,1能被 i(i=1)整除 第 2 个位置(i=2)上的数字是2,2能被 i(i=2)整除 第 2 个优美的排列是 [2, 1]: 第 1 个位置(i=1)上的数字是2,2能被 i(i=1)整除 第 2 个位置(i=2)上的数字是1,i(i=2)能被 1 整除 AC代码: # include <bits/stdc++.h> using namespace std ; int n , ans , k ; int a [ 25 ] ; bool vis [ 25 ] ; void dfs ( int m ) { for ( int i = 1 ; i <= n ;

深搜之抽象类DFS

二次信任 提交于 2020-03-10 00:27:38
抽象类DFS 上次总结了dfs迷宫类,详见我博客: 深搜之迷宫类 最近刷了一些蓝桥杯的真题,这次就总结一下没有图的抽象类的深搜下面是从刷的蓝桥杯真题和计蒜客中总结的一些抽象dfs题型 抽象深搜常见有以下两种类型: 1.凑算式类 2.排列组合类 (一)、凑算式类 九数组分数 /* 1,2,3...9 这九个数字组成一个分数,其值恰好为1/3,如何组法? //答案: //5823 17469 //5832 17496 */ 思路:九位数字组成一个分数1/3 只能是分母5位,分子4位 package 凑算式类 ; public class 九数组分数 { //分子为四位数 分母为五位数 static int [ ] a = new int [ 9 ] ; static boolean [ ] vis = new boolean [ 10 ] ; static boolean f ; static void dfs ( int index ) { //表示试填第index位 // if(f) { // return; // } //在这里输出结果否则存放在数组中的结果可能在return后被修改了 if ( index == 9 ) { //凑到了最后一位 int s = ( a [ 0 ] * 1000 + a [ 1 ] * 100 + a [ 2 ] * 10 + a [ 3 ] )

算法导论学习笔记第26章 & acm专题训练7——最大流

白昼怎懂夜的黑 提交于 2020-03-10 00:09:44
26最大流 1.研究的问题 可以把最大流问题用货运公司的运货来模拟。有一个源点持续不断地产生新货物,并通过有限条道路运往一个汇点,每条道路有限定的容量,且进入一个节点的速度和出一个节点的速度相同。求源点到汇点的最大速率。 2.运用算法条件 容量值为非负数,对于两个节点,u,v,(u,v)与(v,u)至多存在一个,如果不连通,令c(u,v)=0,不允许自循环,图必须连通. c(u,v)指的是容量,f(u,v)指的是流量 3.使实际情况满足条件的修改 (1)解决双向边问题 对于双向边(u,v),添加一个新的节点v’,将c(v,u)=0,连通(v,v’),(v’,u),让它们的容量等于之前的c(v,u)。 (2)解决多个源节点与多个汇点的问题 设立一个超级源节点s和超级汇点t,让超级源节点s到每个源节点的流量为无穷大,设立一个超级汇点,让每个汇点到超级汇点t的流量为无穷大。 4.Ford-Fulkerson方法 算法核心:沿着增广路径重复增加路径上的流量,直到 先引入三个概念 (1)残存网络 由原图G诱导出来的新图Gf 由那些仍有空间对流量进行调整的边构成 边cf(u,v)=c(u,v)-f(u,v) 为了表示对一个正流量(u,v)的缩减,将边(v,u)加入G,将其残存容量设置为f(u,v),一条边的反向流量最多将其正向流量抵消 (2)增广路径 一条从源节点s到汇点t的简单路径

[学习笔记]线段树合并

橙三吉。 提交于 2020-03-09 20:06:38
1、[POI2011]ROT-Tree Rotations 分析:线段树合并人生第一题。 网上的题解我都没看懂……我自己讲一下好了 线段树合并就是把两棵权值线段树合并到一棵 那怎么合并呢? 假设有这么两棵树: 一个结点代表一段值域区间有几个数,那么可以看出合并后应该是这样的 然后具体步骤就是找到一个结点,如果一个结点一棵树上有一棵树上没有,那么直 接返回那个结点的编号,否则两个值域的和相加,递归至左儿子和右儿子 每次合并的复杂度为两棵线段树的点数相加 这道题可以算出左儿子的逆序对个数,右儿子的逆序对个数,然后求出 \((x,y)\) 的对数, $x\in $ 左儿子, $y\in $ 右儿子 每次记录一下 \(sum\) ,在每次合并的时候 \(sum[lson[x]]\times sum[rson[y]]\) 和 \(sum[rson[x]]\times sum[lson[y]]\) 中取个最小值算进答案的贡献就可以了(不懂可以自己画图或看代码理解一下) \(Code\ Below:\) #include <bits/stdc++.h> #define ll long long using namespace std; const int maxn=200000+10; int n,L[maxn*24],R[maxn*24],sum[maxn*24],cnt; ll ans

算法和数据结构 相同的树

隐身守侯 提交于 2020-03-09 13:12:00
class Solution { public: bool isSameTree(TreeNode* p, TreeNode* q) { return dfs(p, q); } bool dfs(TreeNode *pt, TreeNode *qt) { if(pt == NULL && qt == NULL) return true; if(pt == NULL && qt != NULL) return false; if(pt != NULL && qt == NULL) return false; return (pt->val == qt->val) && dfs(pt->left, qt->left) && dfs(pt->right, qt->right); } };    来源: https://www.cnblogs.com/yangwenhuan/p/12448006.html

dsu on tree详解

若如初见. 提交于 2020-03-09 11:30:17
这个算法还是挺人性化的,没有什么难度 就是可能看起来有点晕什么的。 大体 思想是 利用重链刨分来优化子树内部的查询。 考虑一个问题要对每个子树都要询问一次。我们暴力显然是 \(n^2\) 的。 考虑一下优化这个过程,我们发现儿子的信息可以给父亲用但是不能给兄弟或兄弟里的儿子用。 如果是最大最小值我们只能暴力来搞 但如果是出现次数什么的我们可以利用捅差分来解决这个事情。 考虑我们每次先暴力扫轻儿子然后 再做重儿子然后再把轻儿子的代价加上算当前节点的代价然后再把轻儿子的代价给删掉。 我们发现轻儿子被加上删掉两次 而重儿子只做一次并且保留。 可以发现这样做的复杂度很低 考虑一个点到根有logn条轻边所以这样最坏一个点被暴力来回扫logn次 统计自身答案的时候被扫了1次。 最终复杂度为nlogn 说起来很容易但其实代码还是存在一些细节的 要想好再写。 例题: CF600ELomsat gelral const int MAXN=100010; int n,len,mx; int a[MAXN],cnt[MAXN],root[MAXN],sz[MAXN],son[MAXN]; int lin[MAXN],nex[MAXN<<1],ver[MAXN<<1];ll ans[MAXN],w; inline void add(int x,int y) { ver[++len]=y; nex[len]

DFS

孤人 提交于 2020-03-09 09:53:35
LC46. Permutations 给一个包含不重复元素的集合,返回其所有排列 分析:用dfs,用一个数组vis记录某个元素是否已经被使用,使用的时候 vis[i] = 1 ,回溯的时候 vis[i] = 0 ,用 idx 记录当前排列要放数据的位置 class Solution { public: vector<int> nu, vis, cur; vector<vector<int>> res; int n; void dfs(int idx) { if (idx == n) { res.push_back(cur); return; } for (int i = 0; i < n; ++i) { if (vis[i]) continue; vis[i] = 1; cur[idx] = nu[i]; dfs(idx + 1); vis[i] = 0; } } vector<vector<int>> permute(vector<int>& nums) { n = nums.size(); if (!n) return res; nu = nums; vis.assign(n, 0); cur.assign(n, 0); dfs(0); return res; } }; View Code 来源: https://www.cnblogs.com/betaa/p/12446910

BFS和DFS详解以及java实现

别说谁变了你拦得住时间么 提交于 2020-03-09 06:26:14
图的表示 闲话不多说,首先要介绍的就是图的表示,图最常用的两种表示方法是邻接表和邻接矩阵。顾名思义,这两种办法分别用表和矩阵的方式描述图中各顶点之间的联系 下图展示了两种表示上面这个图的方法 BFS 本文将着重介绍遍历图的两种最常用的方法,分别为广度优先遍历和深度优先遍历,后面会具体介绍为什么这么命名。首先来看广度优先遍历BFS(Breadth First Search),其主要思想是从起始点开始,将其邻近的所有顶点都加到一个队列(FIFO)中去,然后标记下这些顶点离起始顶点的距离为1.最后将起始顶点标记为已访问,今后就不会再访问。然后再从队列中取出最先进队的顶点A,也取出其周边邻近节点,加入队列末尾,将这些顶点的距离相对A再加1,最后离开这个顶点A。依次下去,直到队列为空为止。从上面描述的过程我们知道每个顶点被访问的次数最多一次(已访问的节点不会再访问),而对于连通图来说,每个顶点都会被访问。加上每个顶点的邻接链表都会被遍历,因此BFS的时间复杂度是Θ(V+E),其中V是顶点个数,E是边数,也就是所有邻接表中的元素个数。为了更好的说明这个过程,下图列出了对一个图的BFS的过程 private static void bfs(HashMap<Character, LinkedList<Character>> graph,HashMap<Character, Integer>

矩阵中的路径、机器人路径-------DFS

二次信任 提交于 2020-03-08 22:23:49
Q1:请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径。 [["a","b","c","e"], ["s","f","c","s"], ["a","d","e","e"]] 分析:深度优先搜索遍历 递归参数:i,j:行列索引;k:目标字符串的索引 递归终止条件:1、数组越界。2、字符不匹配。3、当前元素已被访问过-------false 若字符全部匹配,k==len(word)---------------true class Solution: def exist(self, board: List[List[str]], word: str) -> bool: #访问标记数组 visited = [[0]*len(board[0]) for x in range(len(board))] def dfs(k,i,j): #递归终止条件 if k==len(word): return True res = False if 0<=i<len(board) and 0<=j<len(board[0]) and board[i][j]==word[k] and

dfs算法总结

帅比萌擦擦* 提交于 2020-03-08 21:55:37
DFS 深度优先搜索 主要有两种实现方法:栈和递归 什么是DFS?说白了就是一直遍历元素的方式而已,我们可以把它看成是一条小蛇,在每个分叉路口随意选择一条路线走,直到撞到南墙,才会调头返回到上一个分叉路口,走另外一条路,有时候运气很好,撞到了目标点,那么这个算法就结束了。 模板: 参数1 DFS(参数2) { if(返回条件成立) return 参数 ; DFS(进行下一步的搜索遍历) ; 回朔; } 1)if 语句: 作用就是告诉小蛇:是否撞到南墙啦?撞到就返回啦,或者,是否到达终点啦?到了就结束啦! 所以使用DFS解决问题的时候需要思考这两个问题:是否有条件不成立的信息(撞到南墙),是否有条件成立的信息(到达终点)。 还有一个非常重要的信息: 是否需要标记访问节点。 2)作标记 是为了防止重复访问,出现环回 如何标记一个节点是否访问过呢?标记常用方法有数组法和set bool visited[length] ; //数组表示,每访问过一个节点,数组将对应元素置为true Set<类型> set; //建立set,每访问一个节点,将该节点加入到set中去 也可以在原数组上进行标记,具体题目具体分析 3)回朔 这点不能忽略,回退到上一节点,继续向下搜索 总之使用dfs需要考虑三点: a,是否有条件不成立的信息(撞南墙) b,是否有条件成立的信息(到终点) c,是否需要记录节点