dfs

树的直径,树的最长路dp思想

核能气质少年 提交于 2020-02-25 00:07:21
dp一直弱死了,树型dp很多基本的题都不会,最近在刷树型dp的题,把关于树的最长路的思想总结一下: 树的直径:树中距离最远的两点间的距离。 下面说几道题: hdu 2196:对于树上(双向边)的每一个节点求出与其距离最远的点的距离。 这个主要用的思想是两次dfs:一次dfs将 无向图转化为有跟树 (所以一开是一定要是建双向边,不然很可能wa或者tle,记录过程中可以开数组记入父亲节点,也可以在dfs递推过程中以栈的形式记录)求出每个跟节点到其所有的叶子节点的最远距离f[i]和g[i]。再一次dfs求出能够由父亲节点转化得到的最大距离h[i],求h[i]的过程中就有可能用到f[i]和g[i]了,因为如果i节点在其父亲j节点的最远距离f[j]中,那么f[i]就只能由g[j]或者h[j]得到,不然就由f[j]或者h[j]得到,具体可能说的不是特别清。两个dfs综合起来的复杂度只有O(E) poj 1985:求树的直径。个人觉得大概有3种方法。 第一种是如上题hdu2196的写法,求出每个点的最远距离最后取最大值,这样不会增加太多的复杂度,因为每次dfs也都知识O(E)的复杂度。 View Code 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include

POJ 2253 二分 + dfs / Floyd-Warshall

心已入冬 提交于 2020-02-24 12:51:36
大致题意 湖中分布 n 块石头,给出所有石头的 xi, yi 坐标值。青蛙 Freddy 想邂逅 Fiona ,Stone #1 是 Freddy 所在的石头, Stone #2 是 Fiona 所在的石头。求 Freddy 必经之路上要跳过的两块石头间的最短距离。输出精度为小数点后 3 位。2<=n<=200, 0 <= xi,yi <= 1000 方法一 二分 + dfs 求最大距离的最小值,很容易想到二分法。二分上界为 Stone #1 到 Stone #2 的距离。dfs 判断使用权值小于当前 mid 的边时,能否由起点到达目标位置。当前搜索的顶点无法到达目标时进行剪枝。 # include <cstdio> # include <STDLIB.H> # include <cmath> # include <algorithm> # include <iostream> # define min(a,b) (((a) < (b)) ? (a) : (b)) # define max(a,b) (((a) > (b)) ? (a) : (b)) # define abs(x) ((x) < 0 ? -(x) : (x)) # define INF 0x3f3f3f3f # define eps 1e-5 # define M_PI 3.14159265358979323846

POJ 3083 dfs + bfs

喜欢而已 提交于 2020-02-24 06:47:25
大致题意 保证能从 h×w 的迷宫的入口走到出口,出口和入口总是在迷宫边缘且不位于转角处。’#’ ‘代表围墙,’.’ 代表可行空间。只能走水平或者垂直方向,求一直靠左走,一直靠右走以及最短路的距离。3 <= w, h <= 40 因为最短路除了不越界以及不能通过围墙外,对走法没有要求,简单 bfs 即可。 向左或向右靠墙走,通过上一步的方向可以判断当前搜索方向遍历的顺序。假设向左靠墙走,那么上一个位置的左侧一定有围墙,于是最先搜索的方向应该是上一步前进方向的左侧,然后顺时针搜索 4 个方向,向第 1 个遍历到的合法方向前进。 实现上向左靠墙走使用顺时针方向的向量数组,这样保证每一步的处理都是一致的,即 (pre + 3) % 4 即可得到当前前进方向。向右靠墙走同理,实现上复用顺时针方向的数组,处理的时候遍历顺序以及向量乘以 -1 即可。 # include <cstdio> # include <STDLIB.H> # include <algorithm> # include <iostream> # include <queue> # define min(a,b) (((a) < (b)) ? (a) : (b)) # define max(a,b) (((a) > (b)) ? (a) : (b)) # define abs(x) ((x) < 0 ? -(x) : (x

2014-10-28 NOIP模拟赛

北城以北 提交于 2020-02-23 03:38:07
Porble 1 时间与空间之旅(tstrip.*) 题目描述 公元22××年,宇宙中最普遍的交通工具是spaceship。spaceship的出现使得星系之间的联系变得更为紧密,所以spaceship船长也成了最热门的职业之一。当然,要成为一名出色的船长,必须通过严格的考核,例如下面是最简单的问题中的一个。 用1~n的整数给n个星系标号,目前你在标号为1的星系,你需要送快递到标号为n的星系,星系之间由于存在陨石带,并不是都可以直连的。同时,由于超时空隧道的存在,在某些星系间飞行会出现时间静止甚至倒流,飞行时间为0或为负数。另外,由星系i到星系j的时间和由星系j到星系i的时间不一定是相同的。 在寄出日期之前收到快递被认为是不允许的,所以每部spaceship上都有一个速度调节装置,可以调节飞行的时间。简单来说其功能就是让所有两个星系间的飞行时间(如果可以直达)都增加或减少相同的整数值,你的任务就是调整速度调节器,找出一条用最短时间完成任务的路径,并且保证这个最短时间的值大于或等于0。 输入格式 输入文件包含多组数据,第1个数为T,表示数据的数量。 对于每一组数据,输入第1行为两个正整数N(2≤N≤100),E(1≤E≤N*(N-1)/2),为星系的个数和星系间飞行的路线数。然后E行,每行三个整数i,j和t(1≤i,j≤N,i≠j,-100000≤t≤100000)

分治 -- 平面最近点对

半世苍凉 提交于 2020-02-22 14:40:14
平面最近点对 : 分析各种情况 : 首先将所有点对按照 x 作为第一关键字进行排序,然后从中间进行劈开,进行递归分治 最后答案就是 res = min(l -- mid,mid + 1 -- r); 从上图可以得知 : 要求在这个平面内所有点中的最近点对,会有三种情况: 1、两个点都在左侧 2、两个点都在右侧 3、一个点在左侧,一个点在右侧 分别向两侧递归进行分治 : 寻找最近点对 : 1、找到左侧的最近点对 2、找到右侧的最近点对 进行比较我们就会得到一个左侧和右侧之中的最近的一对 这时我们会得到一个最近点对的距离(是目前这个过程中最近的一对,假设 当前最近点对的距离是 res) 还差第三种情况 : 第三种情况是一个在左侧,一个在右侧,那么这些点一定是靠近 中间的 mid 的, 所以第三种情况的所有点一定是下面这种情况 (虚线的范围代表这些点可能会出现的范围): 由于我们得到的最近点对的距离是 res,所以剩下的距离一定是要 < res 的,最多 == res,所以我们可以 求出在这个范围内与每个点可能会组成的点的数量,然后,按照纵坐标排序枚举这些(数量不会太多,不用担心会超时) (如上图所示,最多只会有 6 个点 -- 每个方格内最多放一个点) Code : #include <cmath> #include <cstdio> #include <string>

PAT Advanced 1155 Heap Paths (30) [DFS, 深搜回溯,堆]

我怕爱的太早我们不能终老 提交于 2020-02-22 13:16:13
题目 In computer science, a heap is a specialized tree-based data structure that satisfies the heap property: if P is a parent node of C, then the key (the value) of P is either greater than or equal to (in a max heap) or less than or equal to (in a min heap) the key of C. A common implementation of a heap is the binary heap, in which the tree is a complete binary tree. (Quoted from Wikipedia at https://en.wikipedia.org/wiki/Heap_ (data_structure)) One thing for sure is that all the keys along any path from the root to a leaf in a max/min heap must be in non-increasing/non-decreasing order. Your

递归、DFS感觉好难理解啊

扶醉桌前 提交于 2020-02-22 12:46:04
都说递归是一种易于理解的编码方式,但是感觉并没有那么轻松。 今天刷leetCode遇到一个分割回文串的问题,如下: 给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。 返回 s 所有可能的分割方案。 示例: 输入: "aab" 输出: [ ["aa","b"], ["a","a","b"] ] 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/palindrome-partitioning 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 其中就有运用DFS和回溯的解法 完整代码如下 package com.LeeCode;import java.util.ArrayList;import java.util.List;public class VariesPalindrome { List<List<String>>list=new ArrayList<List<String>>(); String s; public List<List<String>> partition(String s) { //从头到尾递归+回溯。 this.s=s; //这个是满足的每一个集合 List<String>ll=new ArrayList<String>(); dfs(ll,0); return

LeetCode 216. Combination Sum III(DFS)

為{幸葍}努か 提交于 2020-02-22 12:32:43
题目 题意:从1-9中选出k个数之和等于n,这个k个数不能有相同的,输出所有可能的k个数字的集合,结果也不能重复 题解:暴搜,从n开始,每次减去1-9中的某个数字,然后继续递归。要注意剪枝,比如1-9中的数字大于n/k的是不可能存在答案中的,如果n 的值小于sum[k]也是不会有答案的。sum[k]表示k个数字最小和的组合。当然k>=10的时候,也是没有答案的。 class Solution { public: vector<vector<int>> res; vector<int> ans; map<int,int>m; int sum[10]={0,1,3,6,10,15,21,28,36,45}; vector<vector<int>> combinationSum3(int k, int n) { if(k==0) return res; fun(n,k); return res; } void fun(int n,int k) { if(k==0) { if(n==0) res.push_back(ans); return; } if(n < sum[k] || k>=10) return; int i=1; if(ans.size()!=0) i = ans[ans.size()-1] + 1; for(;i<=9&&i<=n/k;i++) { if(m[i]!=0)

PAT刷题日志 2020/2/20

牧云@^-^@ 提交于 2020-02-22 04:31:22
开始图的部分: 第一题:1013 Battle Over Cities (25分) 这个题目大意就是给出一个无向图,现在每次删除其中的一个点,然后问剩余部分需要添加几条边才能连接起来,相当于计算剩余部分的连通区域个数,其实可以用dfs进行遍历,遇到删除点就return停止,然后访问过的点设置为true,然后连通区域个数+1,这样遍历完一遍图就可以统计出来互相独立的连通区域个数。 不过对于这个题我第一想到的是刚学过的并查集,不过由于我是并查集新手,尝试实现的时候并没有达到效果,还好参考了算法笔记豁然开朗。 并查集需要对不同的删除点创建不同的并查集合,然后统计根节点的个数,相对还是比较有意思的。 第二题:1021 Deepest Root (25分) 这个我完全按自己的想法,用了并查集合dfs写出来,提交直接AC,感觉很爽,不过跑出来了900ms,哈哈 这个题其实也可以不用并查集,也可以用一个flag数组配合dfs进行遍历所有节点,这样也可以判断连通分量。 第三题:1034 Head of a Gang (30分) 这个比较复杂,不仅统计连通分量,还要计算每个的权值以及总的权值, ohh,我写了至少两个小时,改了bfs和dfs,最终竟然都得了20分,而且错的地方都是一样的。。。。。好吧,超出能力。。 来源: CSDN 作者: 如椽大笔_S686 链接: https://blog

HDU 1521 排列组合 搜索

荒凉一梦 提交于 2020-02-19 15:19:09
排列组合 Problem Description 有n种物品,并且知道每种物品的数量。要求从中选出m件物品的排列数。例如有两种物品A,B,并且数量都是1,从中选2件物品,则排列有"AB","BA"两种。 Input 每组输入数据有两行,第一行是二个数n,m(1<=m,n<=10),表示物品数,第二行有n个数,分别表示这n件物品的数量。 Output 对应每组数据输出排列数。(任何运算不会超出2^31的范围) Sample Input 2 2 1 1 Sample Output 2 AC代码 #include<bits/stdc++.h> using namespace std; int n,m,s,a[11]; void dfs(int x){ if(x==0){ s++;return; } for(int i=0;i<n;++i){ if(a[i]){ a[i]--; dfs(x-1); a[i]++; } } } int main(){ while(cin>>n>>m) { s=0; for(int i=0;i<n;i++) { scanf("%d",&a[i]); } dfs(m); cout<<s<<endl; } return 0; } dfs 如果只要求找到解,不需要回溯 如果需要找出所有解则需要 来源: https://www.cnblogs.com/m2364532