vis

【学习笔记】 Johnson 全源最短路

泪湿孤枕 提交于 2020-01-31 20:16:32
前置扯淡 一年多前学的最短路,当时就会了几个名词的拼写,啥也没想过 几个月之前,听说了 “全源最短路” 这个东西,当时也没说学一下,现在补一下(感觉实在是没啥用) 介绍 由于 \(spfa\) 容易被卡,实际上我们在 \(O(nlog \space n)\) 的算法只有堆优化的 \(Dijkstra\) 由于先天问题, \(Dijkstra\) 无法处理在负权图上的问题 所以“ \(Johnson\) 全源最短路”算法就应运而生了 算法流程 我们针对 \(Dijkstra\) 无法处理负权图进行优化 我们考虑如何把每条边的权值转化成正数 这里引入 “势能” 的概念 势能需要一个起始点:建立一个虚拟源点(类网络流?),向每一个点连一条权值为 \(0\) 的有向边 跑一遍 \(spfa\) ,记录每个点到虚拟源点的最短路,记为 \(res[]\) (这里问显然 \(dis=0\) 的同学,请注意这可能是一个负权图) 然后我们把每一条边的边权操作一下: e[num].dis+=res[e[num].from]-res[e[num].to]; 这里 \(e[]\) 是前向星式建图 这样我们保证了每条边的权值都是正数(思考易得) 然后我们跑 \(n\) 次 \(Dijkstra\) ,最后 ans[from][to]-=res[from]-res[to]; 复杂度 \(O(n^2

纪念品分组

瘦欲@ 提交于 2020-01-31 13:34:48
传送门 题意: 把n个纪念品分组,每组的价格之和<=w,并且每组最多两个纪念品 排序,i从最小的开始,j从最大的开始,符合题意,标记,j–; 不符合的话,j单独一组,j–;直到符合题意的出现 #include <bits/stdc++.h> using namespace std; int n,p[30010],w,vis[30010]; int cnt; int main(){ //freopen("in","r",stdin); ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin >> w >> n; int i; for(i = 0; i < n; i++) cin >> p[i]; sort(p,p+n); i = n - 1; for(int j = 0; j < n; j++){ if(vis[j] && vis[i]) break; if(vis[i] || vis[j]){ cnt++; break; } if(p[j] + p[i] <= w){ vis[i] = vis[j] = 1; cnt++; i--; }else { while (p[j] + p[i] > w) { vis[i] = 1; cnt++; i--; } vis[i] = vis[j] = 1; cnt++; i--; } }

树径问题 最长路问题。。

浪尽此生 提交于 2020-01-31 12:43:33
先看看理论: 假设 s-t这条路径为树的直径,或者称为树上的最长路 现有结论,从任意一点u出发搜到的最远的点一定是s、t中的一点,然后在从这个最远点开始搜,就可以搜到另一个最长路的端点,即用两遍广搜就可以找出树的最长路 证明: 1 设u为s-t路径上的一点,结论显然成立,否则设搜到的最远点为T则 dis(u,T) >dis(u,s) 且 dis(u,T)>dis(u,t) 则最长路不是s-t了,与假设矛盾 2 设u不为s-t路径上的点 首先明确,假如u走到了s-t路径上的一点,那么接下来的路径肯定都在s-t上了,而且终点为s或t,在1中已经证明过了 所以现在又有两种情况了: 1:u走到了s-t路径上的某点,假设为X,最后肯定走到某个端点,假设是t ,则路径总长度为dis(u,X)+dis(X,t) 2:u走到最远点的路径u-T与s-t无交点,则dis(u-T) >dis(u,X)+dis(X,t);显然,如果这个式子成立, 则dis(u,T)+dis(s,X)+dis(u,X)>dis(s,X)+dis(X,t)=dis(s,t)最长路不是s-t矛盾 有了这个基础 求解这道题目就很简单了 两次dfs就解决问题了 多说两句 dfs终止条件的设定。,。 太死板了 这里结束的条件是搜索不下去的时候 那么这里多加一点判断就好了 #include<iostream> #include

leetcode新年病房暴乱康复计划 46. 全排列 JS解法

不羁岁月 提交于 2020-01-30 23:26:27
/** * @param {number[]} nums * @return {number[][]} */ var permute = function(nums) { var ans = []; var vis = []; var res = []; var len = nums.length; function dfs(step){ if(step === len){ ans.push([...res]); return; } for(var i = 0; i < len; i++){ if(!vis[nums[i]]){ vis[nums[i]] = 1; res.push(nums[i]); dfs(step + 1); res.pop(); vis[nums[i]] = 0; } } } dfs(0); return ans; }; 这题经典dfs模板 有手就行 发出来主要是发现js数组类型的length调用时不太划算,需要使用多次时最好拉出来复制一下,这题没设len前运行时间为104ms,优化后80ms 来源: https://www.cnblogs.com/qq965921539/p/12244177.html

HZNU-ACM寒假集训Day3小结

最后都变了- 提交于 2020-01-30 20:57:15
简单搜索 1.DFS UVA 548 树 1.可以用数组方式实现二叉树,在申请结点时仍用“动态化静态”的思想,写newnode函数 2.给定二叉树的中序遍历和后序遍历,可以构造出这棵二叉树,方法是根据后序遍历找到根,然后在中序遍历中找到树根,从而找出左右子树的结点列表然后 递归 构造左右子树 3.注意这里输入的模板,用stringstream会方便 #include<iostream> #include<string> #include<cmath> #include<cstring> #include<vector> #include<map> #include<set> #include<algorithm> #include<queue> #include<stack> #include<sstream> #include<cstdio> #define INF 0x3f3f3f3f const int maxn = 1e6 + 5; const double PI = acos(-1.0); typedef long long ll; using namespace std; const int maxv = 10000 + 10; int in_order[maxv], post_order[maxv], lch[maxv], rch[maxv]; int n; bool

双指针,BFS与图论(一)

﹥>﹥吖頭↗ 提交于 2020-01-30 20:21:49
(一)双指针 1.日志统计 小明维护着一个 程序员 论坛。现在他收集了一份”点赞”日志,日志共有 N 行。 其中每一行的格式是: ts id 表示在 t s 时刻编号 i d 的帖子收到一个”赞”。 现在小明想统计有哪些帖子曾经是”热帖”。 如果一个帖子曾在任意一个长度为 D 的时间段内收到不少于 K 个赞,小明就认为这个帖子曾是”热帖”。 具体来说,如果存在某个时刻 T 满足该帖在 [ T , T + D ) 这段时间内(注意是左闭右开区间)收到不少于 K 个赞,该帖就曾是”热帖”。 给定日志,请你帮助小明统计出所有曾是”热帖”的帖子编号。 输入格式 第一行包含三个整数 N , D , K 以下 N 行每行一条日志,包含两个整数 t s 和 i d 。 输出格式 按从小到大的顺序输出热帖 i d 。 每个 i d 占一行。 数据范围 1 ≤ K ≤ N ≤ 10 5 , 0 ≤ t s , i d ≤ 10 5 , 1 ≤ D ≤ 10000 输入样例: 7 10 2 0 1 0 10 10 10 10 1 9 1 100 3 100 3 输出样例: 1 3 解题思路:排序+双指针 ①对所有的赞按时间排序 ②通过双指针i,j维护长度不大于d的区间,并记录该帖子中的获赞数 #include<iostream> #include <algorithm> #include

缩点

|▌冷眼眸甩不掉的悲伤 提交于 2020-01-29 19:08:47
//kosaraju #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<ctime> using namespace std; const int N=10005; int n,m,cnt,head[N],rhead[N],t,rt,q[N],top,ans,rcnt,Cnt[N],sum[N],number; bool vis[N],rvis[N]; struct Node{ int u,v,next; }edge[N]; struct rNode{ int u,v,next; }redge[N]; void push(int u,int v){ ++cnt; edge[cnt].u=u; edge[cnt].v=v; edge[cnt].next=head[u]; head[u]=cnt; } void rpush(int u,int v){ ++rcnt; redge[rcnt].u=u; redge[rcnt].v=v; redge[rcnt].next=rhead[u]; rhead[u]=rcnt; } void kosaraju(int u){ vis[u]=true; for(int

kosaraju

依然范特西╮ 提交于 2020-01-29 18:56:15
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<ctime> using namespace std; const int N=10005; int n,m,cnt,rcnt,head[N],rhead[N],t,rt,ans; bool vis[N],rvis[N]; struct Node{ int u,v,next; }edge[N]; struct rNode{ int u,v,next; }redge[N]; struct Node1{ int id,val; }f[N]; bool cmp(Node1 p,Node1 q){ return p.val>q.val; } void push(int u,int v){ ++cnt; edge[cnt].u=u; edge[cnt].v=v; edge[cnt].next=head[u]; head[u]=cnt; } void rpush(int u,int v){ ++rcnt; redge[rcnt].u=u; redge[rcnt].v=v; redge[rcnt].next=rhead[u]; rhead[u]=rcnt; }

Code[VS] 1332 题解 【Kosaraju】【Tarjan】

丶灬走出姿态 提交于 2020-01-29 17:26:54
Code[VS] 1332 上白泽慧音题解 Tarjan Algorithm Kosaraju Algorithm 题目传送门: http://codevs.cn/problem/1332/ 题目描述 Description 在幻想乡,上白泽慧音是以知识渊博闻名的老师。春雪异变导致人间之里的很多道路都被大雪堵塞,使有的学生不能顺利地到达慧音所在的村庄。因此慧音决定换一个能够聚集最多人数的村庄作为新的教学地点。人间之里由N个村庄(编号为1..N)和M条道路组成,道路分为两种一种为单向通行的,一种为双向通行的,分别用1和2来标记。如果存在由村庄A到达村庄B的通路,那么我们认为可以从村庄A到达村庄B,记为(A,B)。当(A,B)和(B,A)同时满足时,我们认为A,B是绝对连通的,记为<A,B>。绝对连通区域是指一个村庄的集合,在这个集合中任意两个村庄X,Y都满足<X,Y>。现在你的任务是,找出最大的绝对连通区域,并将这个绝对连通区域的村庄按编号依次输出。若存在两个最大的,输出字典序最小的,比如当存在1,3,4和2,5,6这两个最大连通区域时,输出的是1,3,4。 输入描述 Input Description 第1行:两个正整数N,M 第2..M+1行:每行三个正整数a,b,t, t = 1表示存在从村庄a到b的单向道路,t = 2表示村庄a,b之间存在双向通行的道路

P2294 [HNOI2005]狡猾的商人

℡╲_俬逩灬. 提交于 2020-01-29 16:50:39
题目描述 输入输出格式 输入格式: 从文件input.txt中读入数据,文件第一行为一个正整数w,其中w < 100,表示有w组数据,即w个账本,需要你判断。每组数据的第一行为两个正整数n和m,其中n < 100,m < 1000,分别表示对应的账本记录了多少个月的收入情况以及偷看了多少次账本。接下来的m行表示刁姹偷看m次账本后记住的m条信息,每条信息占一行,有三个整数s,t和v,表示从第s个月到第t个月(包含第t个月)的总收入为v,这里假设s总是小于等于t。 输出格式: 输出文件output.txt中包含w行,每行是true或false,其中第i行为true当且仅当第i组数据,即第i个账本不是假的;第i行为false当且仅当第i组数据,即第i个账本是假的。 输入输出样例 输入样例#1: 2 3 3 1 2 10 1 3 -5 3 3 -15 5 3 1 5 100 3 5 50 1 2 51 输出样例#1: true false Solution:   本题是思维比较巧妙的差分约束。。。   思路类似于植树那道题,$u\rightarrow v=c$可以理解为$sum[v]-sum[u-1]=c$(前缀和)。   那么对于每个条件我们可以先得出约束条件:$w[u-1,v]=c$表示$sum[v]$比$sum[u-1]$大$c$。   我们直接在这样的图上跑最长路后能求出每个点的