dfs

青云的机房组网方案(简单+普通+困难)(虚树+树形DP+容斥)

大城市里の小女人 提交于 2020-01-17 01:46:47
题目链接 1.对于简单的版本n<=500, ai<=50 直接暴力枚举两个点x,y,dfs求x与y的距离。 2.对于普通难度n<=10000,ai<=500 普通难度解法挺多 第一种,树形dp+LCA 比赛的时候,我猜测对于不为1的n个数,其中两两互质的对数不会很多,肯定达不到n^2 然后找出所有互质的对数,然后对为1的数进行特殊处理。(初略的估计了下,小于500的大概有50个质数,将n个数平均分到这些数中,最后大概有10000*50*200=10^7) 对所有的非1质数对,采用离线LCA可以搞定。 对于1的特殊情况,只需要用两次dfs,就可以找出所有1到其它点的距离和与1之间的距离和。 第二种,树形dp+容斥 这种方法从边的角度,考虑每一条边会被计算多少次,这也是树上求距离的常用方法。 由于树边都是桥边,所有只要求出边两边联通块之间互质对数。最简单的想法即是枚举每一条边,然后再分别枚举两边区域,这样的复杂度是500*500*10000 很遗憾并没有这么简单。于是用容斥原理进行优化。在枚举某条边的一边的x(1<=x<=500)的时候,考虑右边为x质因子倍数的情况,也就是容斥了。 这样可以将复杂度变为10000*500*k*2^k( k<=4) 官方题解: 附上代码: // // main.cpp // 160701 // // Created by New_Life on 16/7

《算法竞赛进阶指南》0.2递推与递归

允我心安 提交于 2020-01-17 01:06:10
92. 递归实现指数型枚举 从 1~n 这 n 个整数中随机选取任意多个,输出所有可能的选择方案。 输入格式 输入一个整数n。 输出格式 每行输出一种方案。 同一行内的数必须升序排列,相邻两个数用恰好1个空格隔开。 对于没有选任何数的方案,输出空行。 本题有自定义校验器(SPJ),各行(不同方案)之间的顺序任意。 数据范围 1≤n≤15 输入样例 : 3 输出样例: 3 2 2 3 1 1 3 1 2 1 2 3 #include <iostream> using namespace std; int n; void dfs(int u, int state) { if(u == n) { for(int i = 0; i < n; i++) if(state >> i & 1) cout << i + 1 << " "; cout << endl; return; } dfs(u + 1, state); // 不选 dfs(u + 1, state | 1 << u); //选,整数二进制表示下的第u位赋值1 } int main() { cin >> n; dfs(0,0); return 0; } 93. 递归实现组合型枚举 从 1~n 这 n 个整数中随机选出 m 个,输出所有可能的选择方案。 输入格式 两个整数 n,m,在同一行用空格隔开。 输出格式

DFS及有向图的拓扑排序

痴心易碎 提交于 2020-01-16 14:59:50
一个有向图的DFS森林可能具有的全部类型的边: 树向边、回边、从顶点到树中非子女子孙的前向边、交叉边。所有不属于前三种类型的边都属于交叉边。 一条回边的存在意味着有向图具有一个有向的回路。如果一个有向图的DFS森林没有回边,该有向图是一个无环有向图,即有向无环图的简称。 拓扑排序: 按某种次序列出有向图中的顶点,使得对于图中每一条边来说,边的起始顶点总是排在边的结束顶点之前。这个问题称为拜年排序。 拓扑排序的两个算法: 1,DFS。 执行一次DFS遍历,并记住顶点变成死端(即退出遍历栈)的顺序。将该顺序反过来就得到了拓扑排序的一个解。当然,在遍历的时候不能遇到回边。如果遇到一条回边,该图就不是无环有向图,并且对它顶点的拓扑排序是不可能的。 2,基于减治法: 不断地做这样的一件事,在余下的有向图中求出一个源,它是一个没有输入边的顶点,然后把它和所有从它出发的边都删除。如果有多个这样的源,可以任意选择一个。如果这样的源不存在,算法停止,因为该问题是无解的。 来源: https://www.cnblogs.com/cmleung/archive/2011/04/26/2028872.html

AMPPZ2014

本秂侑毒 提交于 2020-01-16 14:53:37
[AMPPZ2014]The Lawyer 记录每天结束的最早的会议以及开始的最晚的会议即可。 #include<cstdio> #define N 500010 int n,m,i,d,a[N],b[N],st[21],en[21]; inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';} int main(){ for(read(n),read(m),i=1;i<=n;i++){ read(a[i]),read(b[i]),read(d); if(!en[d]||b[en[d]]>b[i])en[d]=i; if(!st[d]||a[st[d]]<a[i])st[d]=i; } for(i=1;i<=m;i++)if(!st[i]||b[en[i]]>=a[st[i]])puts("NIE");else printf("TAK %d %d\n",en[i],st[i]); return 0; }    [AMPPZ2014]Petrol 一遍spfa求出d[x]表示离x最近的加油站到x的距离。 对于每条边(x,y,w),将边权重置为d[x]+d[y]+w。

【高手训练】动态规划

核能气质少年 提交于 2020-01-16 09:29:43
T1.成绩单 期末考试结束了,班主任 老师要将成绩单分发到每位同学手中。 老师共有份成绩单,按照编号从到的顺序叠放在桌子上,其中编号为的成绩单分数为。 成绩单是按照批次发放的。发放成绩单时,老师会从当前的一叠成绩单中抽取连续的一段,让这些同学来领取自己的成绩单。 当这批同学领取完毕后,老师再从剩余的成绩单中抽取连续的一段,供下一批同学领取。 经过若干批次的领取后,成绩单将被全部发放到同学手中。 然而,分发成绩单是一件令人头痛的事情,一方面要照顾同学们的心理情绪,不能让分数相差太远的同学在同一批领取成绩单; 另一方面要考虑时间成本,尽量减少领取成绩单的批次数。 对于一个分发成绩单的方案,我们定义其代价为: \(a*k+b*\sum_{i=1}^k(max_i-min_i)^2\) 其中,是方案中分发成绩单的批次数,对于第批分发的成绩单,是最高分数,是最低分数。 是给定的评估参数。现在,请你帮助老师找到代价最小的分发成绩单的方案,并将这个最小的代价告诉老师。 当然,分发成绩单的批次数是由你决定的。 一道题面比较真实的题目 需要离散化,设状态 \(f[i][j][l][r]\) 为在[i,j]表示 \([i,j]\) 区间内取到剩余数字值域为区间 \([l,r]\) 的最小代价。特别的,令 \(f[i][j][0][0]\) 表示 \([i,j]\) 区间取完的最小代价。枚举一个中间点

WHUT第六周训练整理

只愿长相守 提交于 2020-01-16 01:48:12
WHUT第六周训练整理 写在前面的话:我的能力也有限,错误是在所难免的!因此如发现错误还请指出一同学习! 索引 (难度由题目自身难度与本周做题情况进行分类,仅供新生参考!) 零、基础知识过关 一、easy:01、05、06、10、13、14、15、16、20 二、medium:02、04、07、08、09、11、12、18、19、21、22、23、24 三、hard:03、17 本题解报告大部分使用的是C++语言,在必要的地方使用C语言解释。 零、基础知识过关 本周是搜索场,用到的知识全都是两种基础的搜索方法( d f s 、 b f s dfs、bfs d f s 、 b f s )再加上一些细节、剪枝等。 d f s ​ dfs​ d f s ​ :深度优先搜索,对于一颗搜索树先往更深的地方进行搜索,如果找到了答案或者无法继续往更深的地方走则返回,适合于用于寻找是否存在可行解的情况。 b f s ​ bfs​ b f s ​ :广度优先搜索,对于一颗搜索树“一层一层”地搜索,如果找到答案则返回当前的层数,如果无法继续往下走则该答案不存在。 剪枝:在搜索的过程中存在很多不必要的步骤,如果我们明知道这样走没有作用,那么就不需要走了,即剪枝。常见的剪枝有:可行性剪枝、最优性剪枝、奇偶性剪枝等等。 还没有掌握的同学先自行在网上学习,基础的知识必须要熟悉! 总而言之 d f s dfs

浅析树链剖分

依然范特西╮ 提交于 2020-01-15 13:50:07
前言 树链剖分 , 我觉得最精妙的地方就在于它是通过$dfs$序将树形结构转为线性结构便于处理,进而可以用数据结构(线段树、树状数组等)去进行修改和查询。 将复杂的结构转化为相对我们熟悉简单的结构,这个思想对很多问题是通吃的,不仅仅在树形问题,算法中,在其他领域中也常常会用到这种思想 我们先来回顾两个问题 : 1.将树从$x$到$y$结点最短路径上所有节点的值都加上z 我们很容易想到,树上差分可以以 $O(n+m)$的优秀复杂度解决这个问题 2.求树从$x$到$y$结点最短路径上所有节点的值之和 $lca$大水题,我们又很容易地想到, $dfs$ $O(n)$预处理每个节点的$dis$(即到根节点的最短路径长度) 然后对于每个询问,求出$x,y$两点的$lca$,利用$lca$的性质$dis(x,y)=dis(x)+dis(y)-2*dis(lca)$求出结果, 时间复杂度 $O(mlogn+n)$ 现在来思考一个$bug$: 如果刚才的两个问题结合起来,成为一道题的两种操作呢? 刚才的方法显然就不够优秀了(每次询问之前要跑$dfs$更新 $dis$ ) 理解 树剖是通过轻重边剖分将树分割成多条链,然后利用数据结构来维护这些链(本质上是一种优化暴力) 给定一棵有根树,对于每个非叶结点$u$,设$u$的子树中结点数最多的子 树的树根为$v$,则标记$(u,v)$为重边,从$u

文件服务实例工厂实现方案

╄→尐↘猪︶ㄣ 提交于 2020-01-15 07:05:57
// todo 代码可以优化,根据配置文件来.1.3版本中优化 // @Bean // @ConditionalOnProperty(value = "ossclient.active",havingValue = "dfs") // public IOssService dfs() { // return xxx; // } 获取活跃的文件服务实例 /** * 得到活跃的Dfs * * @return {@link com.mamcharge.techc.ossclient.service.IOssService} */ public IOssService getActiveDfs() { //双重锁校验,缓存当前使用的dfs服务下次直接返回 if (iOssService == null) { synchronized (IOssService.class) { if (iOssService == null) { if (ActiveOssStatusEnum.FAST_DFS.getCode().equals(active)) { this.iOssService = ossClientService.getFdfsService(); } else { this.iOssService = ossClientService.getAliossService(); } }

DFS(深度优先搜索)---踩方格

六月ゝ 毕业季﹏ 提交于 2020-01-15 05:51:44
题目描述: 题目描述 有一个方格矩阵,矩阵边界在无穷远处。我们做如下假设: a.每走一步时,只能从当前方格移动一格,走到某个相邻的方格上; b.走过的格子立即塌陷无法再走第二次; c.只能向北、东、西三个方向走; 请问:如果允许在方格矩阵上走n步,共有多少种不同的方案?(2种走法只要有一步不一样,即被认为是不同的方案) 输入 允许在方格上行走的步数n(n≤20)。 输出 计算出的方案数量 样例输入 2 样例输出 7 代码(DFS): # include <cstring> # include <iostream> using namespace std ; const int N = 20 ; //最大步数 int w [ N + 1 ] [ N + 1 ] ; int dfs ( int i , int j , int n ) { if ( n == 0 ) return 1 ; //没步数了,1种走法 else //还有步数可以走 { int m = 0 ; //重新计数(从当前位置到最后的步数) w [ i ] [ j ] = 1 ; //标记(为了保证当前路径不重复) if ( ! w [ i - 1 ] [ j ] ) m + = dfs ( i - 1 , j , n - 1 ) ; //北 if ( ! w [ i ] [ j - 1 ] ) m + = dfs (

PAT 甲 1126 Eulerian Path (25分)

巧了我就是萌 提交于 2020-01-15 01:48:18
要点1:注意考察图的连通性,用dfs,看看一次dfs能否遍历所有的点,如果不联通,就不是欧拉图 要点2:会出现所有的点都在边里,但还是不联通的情况,所以必须用dfs,不能直接看点有没有被输入过 #include<iostream> #include<map> #include<vector> using namespace std; int n,m,cnt; vector<int> graph[505]; bool vis[505]; void dfs(int index){ if(vis[index]==true) return; vis[index]=true; ++cnt; for(auto i:graph[index]){ dfs(i); } } int main(){ cin>>n>>m; while(m--){ int v1,v2; cin>>v1>>v2; graph[v1].push_back(v2); graph[v2].push_back(v1); } int odd=0; for(int i=1;i<=n;++i){ int degree=graph[i].size(); cout<<degree; if(i<n) cout<<" "; if(degree%2==1) odd++; } cout<<endl; dfs(1); if(cnt==n&&odd==0