NOIP冲刺!!!!!

经过我的专断独行长久的讨论,我们仨决定在noip即将到来的7天内每天一个大主题,每人一个分块进行学习复习总结

不管怎么样都要继续努力!!

11.27 周五

今天早放学所以没有训练时间了...但勤劳的我自然还是要复习的!

今天自然不准备写什么了,主要是自己的复习,正式复习从明天开始,这两天都是图论哦

图论——连通性问题

 

首先对于图论中的基本概念以及求割点是说过的(但不一定记得)所以基础概念直接写一下当做回忆

强连通:在一个有向图G里,设两个点 a b 发现,由a有一条路可以走到b,由b又有一条路可以走到a,我们就叫这两个顶点(a,b)强连通。

连通图:在一个无向图 G 中,若从顶点i到顶点j有路径相连,则称i和j是连通的。如果图中任意两点都是连通的,那么图被称作连通图。如果此图是有向图,则称为强连通图。

割点:对于一个点x∈无向连通图G,若从图中删去改点以及与该点相连的所有边之后,G分裂为两个或两个以上不相连的子图,则称x为G的割点。

 

割点

稍微回顾一下tarjan算法:

时间戳:在BFS过程中,按照每个节点被第一次访问的顺序,依次给予 N个节点1~N个整数标记。记为dfn[x]。

追溯值:表示顶点u及其子树中的点,通过非父子边(回边),能够回溯到的最早的点(dfn最小)的dfn值。记为low[x]。

如果x不是根节点,x是割点当且仅当搜索树上存在x的一个子节点y,满足dfn[x]<=low[y]。

若x为根节点,x是割点当且仅当x存在2棵以上子树。

原理很简单:若子节点y的low值>=父节点x的dfn值,说明y只能通过x这一个点与其他点相连,则删去x点后,原图G将分裂为两个不相连的子树。

球法

假设当前顶点为u,则默认low[u]=dfn[u],即最早只能回溯到自身。

有一条边(u, v),如果v未访问过,继续DFS,DFS完之后,low[u]=min(low[u], low[v]);

如果v访问过(且u不是v的父亲),就不需要继续DFS了,一定有dfn[v]<dfn[u],low[u]=min(low[u], dfn[v])。 

 

例题:洛谷P3388 割点

模板代码:

 1 #include<cmath>
 2 #include<cstdio>
 3 #include<string>
 4 #include<cstring>
 5 #include<iostream>
 6 #include<algorithm>
 7 using namespace std;
 8 const int N=2e5+10,M=2e5+10;
 9 struct mac
10 {
11     int to;
12     int next;
13 }edge[M];
14 int head[N],ednum=0;//链式前向星 
15 void add(int u,int v)
16 {
17     ednum++;
18     edge[ednum].next=head[u];
19     edge[ednum].to=v;
20     head[u]=ednum;
21 }
22 int num[N],low[N];//各点时间戳、最小时间戳
23 bool ans[N];//答案 
24 int indx,cnt=0;//时间戳、答案个数 
25 void tarjan(int u,int fa)
26 {
27     int child=0,v;
28     indx++;
29     num[u]=low[u]=indx;
30     for(int i=head[u];i!=0;i=edge[i].next)
31     {
32         v=edge[i].to;
33         if(!num[v])
34         {
35             tarjan(v,fa);
36             low[u]=min(low[u],low[v]);
37             if(low[v]>=num[u]&&u!=fa&&!ans[u])//子节点最小时间戳大于父节点且父节点并非根节点 
38             {
39                 ans[u]=1;
40                 cnt++;// 保证u未被标记过之后累计答案数量 
41             }
42             if(u==fa)
43             child++;
44         }
45         low[u]=min(low[u],num[v]);//此处不能用else    
46     }
47     if(u==fa&&child>=2&&!ans[u])
48     {
49         ans[u]=1;
50         cnt++;
51     }
52 }
53 int main()
54 {
55     //freopen(".in","r",stdin);
56     //freopen(".out","w",stdout);
57     int n,m,u,v;
58     scanf("%d%d",&n,&m); 
59     for(int i=1;i<=m;i++)
60     {
61         scanf("%d%d",&u,&v);
62         add(u,v);
63         add(v,u);
64     }
65     for(int i=1;i<=n;i++)//求每个连通块的割点
66     {
67         if(num[i]==0)
68         tarjan(i,i);
69     }
70     printf("%d\n",cnt);
71     for(int i=1;i<=n;i++)
72     {
73         if(ans[i])
74         printf("%d ",i);
75     }
76     return 0;
77 }
蒟蒻代码

需要注意几件事:

1.若该点v已被访问过,又通过边(u,v)来到v,v的low值是low[v]值与dfn[n]的最小值,而不是low[v]与low[u]的最小值,原因可以参看这里

2.给的图不一定是连通图,所以要注意是求每个连通块的割点。

 

割边

与割点类似,使用tarjan算法。但是判定与写法略有不同。

判定:若搜索树上存在x的一个子节点y,满足dfn[x]<low[y],则边(x,y)为一个割边。

因为dfn[x]<low[y]说明从y出发,在不经过(x,y)的情况下,无论走哪条边都无法到达x,所以将边(x,y)删掉后,原图G将分裂为两个不相连的子图。

·为什么没有等于号:在相等时说明存在其他边链接x与y。删除该边对原图连通性没有贡献。但是割点中若两值相等则证明y不经过(x,y)到达的时间戳最小的点依旧是x,则删除x可以使y与其他点分离。

·重边的处理方法:x是y的父亲(不是父亲的话重边对算法无影响),当x与y点中间有多条边的时候,(x,y)一定不是桥。在这些重复的边中,只有一条边算是搜索树上的边,故此时可以用dfn[x]来更新low[y](若没有重边,是不能用父节点的dfn更新子节点的low值的)。算法进阶指南中提供了一种使用临接表存图解决的方法,这里介绍另一种解决方法(来自博客):

设一个布尔值,如果是父节点第一次不予通过并把布尔值标记为一,当有重边的时候,这条边一定会再次访问,此时发现布尔值为一,直接更新。

下面是代码(洛谷没有割边模板题,可以自行寻找):

 1 void tarjan(int u, int fa)
 2 {
 3     dfn[u] = low[u] = ++dfs_clock;
 4     bool flag = false;
 5     for(int i=0; i<g[u].size(); ++i)
 6     {
 7         int v = g[u][i];
 8         if(v==fa && !flag)//如果有重边,那么边(u,v)被存了两次,所以,如果第二次访问,就让他通过
 9         {
10             flag = true;
11             continue;
12         }
13         if(dfn[v]==0)
14             tarjan(v,u);
15         low[u] = min(low[u],low[v]);
16         if(low[v] > dfn[u])
17             cntCut++;
18     }
19 }
核心代码

以上。

11.28 周六

今天又是考试!果不其然凉凉又迟到了...等等....是就没来啊!一觉睡到16点就过分了啊!

今天的考试难度较为简单,A了1道题,第二道其实60分知道怎么做,但01背包调!不!出!来!

PS:先写的贪心但是无法证明于是用了动归,谁知道贪心居然是对的!

果然我只有脚而已。

接下来继续昨天内容。

此乃ydy负责部分内容:

并查集

 

强连通分量

你以为我要讲缩点?

错啦!其实讲缩点之前还要学强连通分量+拓扑排序+DP哒!

....

好吧一个一个来

首先缩点,顾名思义,就是将有向有环图上的环缩成一个一个点。而求环就是缩点要做的第一件事。

所谓的环,就是我们所说的强连通分量:即在有向图中的一个强连通子图(子图上的点都能互相到达)

求强连通分量自然可以想到使用Tarjan算法。

靠好累啊!!!

 

11.29  周日

缩点

我 好 慢 啊

洛谷P3387 缩点

题目背景

缩点+DP

题目描述

给定一个 n 个点 m 条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大。你只需要求出这个权值和。

允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次。

输入格式

第一行两个正整数 n,m

第二行 n 个整数,依次代表点权

第三至 m+2行,每行两个整数 u,v,表示一条 uv 的有向边。

输出格式

共一行,最大的点权之和。

输入输出样例

输入 #1
2 2
1 1
1 2
2 1
输出 #1
2

说明/提示

【数据范围】
对于 100% 的数据,1n1041m105,点权[0,1000]

算法:Tarjan 缩点 + DAGdp

 

posted @ 2020-11-27 18:36  许肆玖  阅读(133)  评论(2编辑  收藏  举报