zoukankan      html  css  js  c++  java
  • ZROI 19.07.30 简单图论/kk

    1.最短路

    • NOI2019 D2T1

    我被这题送Fe了/lb

    只有zz才会写二维线段树,比如我。

    实际上你只需要矩形取min就可以。

    kd-tree可以随便过,最慢的点(0.1s)

    另外一种简单做法是把边压到堆里,每次找到的最小(出发点+边权)的边一定是最优的,然后清空对应的矩形,线段树套set或者并查集都可以过。(stO _rqy Claris Orz)


    • (n)个点,(m)条边的DAG,求删去每个点后(1)(n)最短路。(n,m leq 3 imes 10^5)

    拓扑排序之后,对每个点(x)预处理出(f_x,g_x),分别表示(1->x)(x->n)的最短路。

    按照拓扑序考虑每个点(x),同时维护两个集合(A,B),分别表示拓扑序在(x)前、后的点。

    这样答案一定形如$f_a+g_b+(a, b), a in A,bin B $。

    用堆维护上述结构,当(x)转移到(x+1)时,只需把(x)加入(A),并把(x+1)(B)中移除,并处理相应影响即可。


    • (n)个点,(m)条边的有向图,计算每个点传递闭包大小,允许误差,最多差两倍。(n,mleq 2 imes 10^5)

    SD省集讲过……然而我又忘了。

    结论:([0,1])之间的(n)个随机变量,最小值的期望是(frac{1}{n+1})

    比较显然。

    缩点之后,给每个点赋一个([0,1])的变量(f_i),然后按照拓扑序执行(f_x=min(f_x, f_y), where~(x,y)~exists.)

    重复若干次,取(f_i)平均值计算,可以证明期望误差不会超过两倍。

    2.生成树

    • (n)个点,(m)条边的无向图,第(i)条边的花费是(2^i)。现在想要经过每条道路至少一次,求最小花费。

    每条边先走一次,然后若干条边需要走两次,使原图成为欧拉回路。

    发现每棵生成树都能做到,选择最小生成树即可。

    统计答案的时候从叶子往根节点统计,简单的树形dp。


    • (n)个点的图,每两个点之间有若干条黑、白边,求恰好(k)条白边生成树个数。

    长见识了……Matrix Tree里不仅可以放整数,也可以放多项式,因为它满足所有四则运算的规律……

    (i,j)间有(a_{i,j})条白边,(b_{i,j})条黑边,则矩阵中(c_{i,j})位置是(a_{i,j}x+b_{i,j})

    这样最后算出行列式是一个(n-1)次多项式,第(i)项的系数是恰好(i)条白边的生成树个数。

    直接计算多项式会很麻烦,但是可以选(n)(x_i)带入多项式计算,然后拉格朗日插值出多项式。复杂度(O(n^4))


    • (n)个点的图,边带权,求所有生成树权值和的(k)次方和。(n,k leq 50, w_i leq 10^9)

    跟上面那题很像,拆开(k)次方之后,矩阵中每个位置都是一个(k)次组合生成函数。最后乘起来是一个((n-1)k)次多项式,选((n-1)k+1)个点插值即可。复杂度(O(n^4k)),反正能过。


    • (n)个点的最小方差生成树,(n leq 10^5,w_i leq 10^9)

    比较暴力的思路:

    (f(x)=sum (v_i-x)^2),发现(f(x))(x)取到平均值时有最小值。即,用别的数来代替平均值,不会使答案变小。

    所以可以枚举平均值(sigma),边按照((v_i - sigma )^2)排序,求最小生成树。

    但是值域过大无法枚举。发现在枚举(sigma)的过程中,本质不同的排序方案只有(m^2)种(两条边会在唯一确定的时刻交换顺序)。

    因此暴力的解法可以做(m^2)次最小生成树,时间复杂度(O(m^3log m))

    考虑优化,发现每条边的贡献是一个(a_i>0)的二次函数,并且所有二次函数的(a_i)相同,这意味着它存在于最小生成树的时间是一段区间。

    如果把边按(w_i)从小到大排序,每条边“能被加入的时候”会踢掉之前在树中的(w_i)最小的边(考虑二次函数的形态,此时这条最小的边的贡献已经越过最低点,开始增长)

    lct维护最大生成树以及边的权值和、权值平方和即可。时间复杂度(O(mlog m))

    3.2-SAT

    • (n)个点,(m)条边,有(k)个集合,满足每个点恰好属于其中一个。每个集合选恰好一个点,使每条边至少选了一个端点。(n,m,k leq 10^6)

    边的限制是2-SAT板子。

    集合的限制比较麻烦,对于每个集合建一个前缀集合(A)和后缀集合(B),存在如下限制:如果(A_i=1),则(A_{i+1}=1);如果(A_{i+1}=0),则(A_{i}=0);如果(A_i=0),则(S_{A_i}=0)(B)的限制同理。

    前后缀法把本来接近完全图的连边优化成了线性。


    • (n)个点((x_i,y_i)),每个点建一个建筑,形如以该点为斜边中心的等腰直角三角形,且斜边平行或垂直于(x)轴,求最大边长。(n leq 60)

    二分答案,把每个点拆成四个小直角三角形。发现对角的两个选且仅能选一个。然后就随便2-SAT了。


    • (n)个点的树,(m)个关键点,给每个关键点确定一个树上位置(p_i),满足(k)个形如“以(p_x)为根,(p_y,p_z)的lca为(w)点”的限制。(n,m leq 100)

    首先限制可以转化为,以(Q)为根时,(p_x,p_y,p_z)两两之间不在同一棵子树里。

    先随便硬点一个点为根,设(f_{x,y})表示关键点(x)是否在树上点(y)的子树里。然后随便连一下边就好了。

    4.欧拉回路

    • (n)个点((x,y)),每个点黑白染色,使得每行每列都满足(|black-white|leq 1),输出方案。(nleq 2 imes 10^5)

    先假设限制缩紧到(|black-white|= 0)且保证有解。

    对行列建二分图,求出一个欧拉回路,则向左为黑,向右为白。

    实际上会有一些点度数为奇数。两边各建一个虚点,向对面奇数点连边。跑出的欧拉回路,每个点至多和一个虚点有边。


    • (n)个点,(m)条边,存在自环的无向图,对于每一个边集的子集,若它的导出子图的每个连通块都存在欧拉回路,则它对答案的贡献为子集边数的平方。(nleq 10^5)

    显然转化为每个点度数都是偶数。

    考虑简化形式:任意子集贡献为(1),即答案为满足条件的子集个数。列出(m)个变量的(n)个xor方程组,答案即为(2^{p})(p)为自由元个数。

    方程组很难解,但仔细观察可以发现,对于每个连通块,任意求一棵生成树,则对于任一种非树边的集合,都可以在生成树上找到唯一的一组解,使得所有点度数为偶数。

    因此对于这种简化形式,答案为(2^{m-n+x}),其中(x)为连通块个数。

    我们发现,对于一个边集,边数的平方等价于在边集中选两条边的方案数。因此我们可以硬点两条边(a, b)必选,计算包含这两条边的方案数。

    如果这两条边涉及了桥边,则两个被分开的连通块里都产生了一个奇数点,且这个奇数点无法消除,所以一定无解。

    如果删去这两条边没有改变连通性,我们可以将这两条边删去,仍然可以找到一棵生成树,但非树边减少了(2),答案为(2^{m-n+x-2})

    同理,若删边后连通块增加了(1)(可以理解为断开了一个环),答案为(2^{m-x+x-1})

    对于判断连通性,可以先对每个连通块生成一棵dfs树(这样只有返祖边),并对每条非树边随机一个ull的权值,对它覆盖的链xor上这个权。如果两条边权值相等,则删除它们后,中间的部分必然会被独立。随便维护一下这个权值就好了。

    实际上不需要枚举,只需要算出各种情况的个数就可以了。

  • 相关阅读:
    20155338 2016-2017-2 《Java程序设计》第4周学习总结
    20155338 2016-2017-2 《Java程序设计》第3周学习总结
    20155338 2006-2007-2 《Java程序设计》第2周学习总结
    20155316 实验三《敏捷开发与XP实践》实验报告
    20155316 2016-2017-2 《Java程序设计》第10周学习总结
    20155316 2016-2017-2 《Java程序设计》第9周学习总结
    20155316 实验二《Java面向对象程序设计》实验报告
    20155316 2016-2017-2 《Java程序设计》第8周学习总结
    20155316 实验一《Java开发环境的熟悉》实验报告
    20155316 2016-2017-2 《Java程序设计》第7周学习总结
  • 原文地址:https://www.cnblogs.com/suwakow/p/11375064.html
Copyright © 2011-2022 走看看