前排提示:先学习拓扑排序,再学习Tarjan有奇效。

--------------------------

Tarjan算法一般用于有向图里强连通分量的缩点。

强连通分量:有向图里能够互相到达的点的集合。(大概是这么个意思,自己意会)

因为能够互相到达,所以宏观上我们可以把它们看成一个点,边权也相应的加起来即可。

下面是Tarjan过程的代码解释:

我们开两个数组,分别为dfn[]和low[]。dfn表示此点的时间戳,low表示最早的时间戳。(即进入某一个环最早的时间戳)

遇到一个没有记录过的点,就把它扔到栈里,不停dfs,直到dfn[]==low[],即某一个环已经遍历完了,我们就弹栈,将这一个环合并。

代码如下:

void tarjan(int now)
{
dfn[now]=low[now]=++cnt;
st[++top]=now;
vis[now]=;
for (int i=head[now];i;i=edge[i].next)
{
int to=edge[i].to;
if (!dfn[to]) tarjan(to),low[now]=min(low[now],low[to]);
else if (vis[to]) low[now]=min(low[now],dfn[to]);
}
if (dfn[now]==low[now])
{
tot++;
while(st[top+]!=now)
{
pos[st[top]]=tot;
sum[tot]+=val[st[top]];
vis[st[top--]]=;
}
}
}

配合拓扑排序,一张新的有向无环图就构造了出来。

-------------------------------------------------------------------------------------

【模板】 缩点

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

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

第一行两个整数,为$n$,$m$。

第二行到第$m+1$行有每行有3个整数,分别为$u,v,d$,表示$u\rightarrow v$有一条长度为$d$的边。

输出格式:一行结果。

-------------------------------------------------

Tarjan模板题,只不过加了一点小DP,记忆化搜索即可。注意的地方就是拓扑排序后的重新建图。

#include<bits/stdc++.h>
using namespace std;
const int maxn=;
int cnt,dfn[maxn],vis[maxn],low[maxn];
int f[maxn],sum[maxn],ans;
int jishu,head[];
int top,st[maxn],pos[maxn],tot;
int n,m,x[maxn],y[maxn],val[maxn];
struct node
{
int next,to;
}edge[];
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)){if (ch=='-') f=-;ch=getchar();}
while(isdigit(ch)){x=x*+ch-'';ch=getchar();}
return x*f;
}
inline void add(int from,int to)
{
edge[++jishu].next=head[from];
edge[jishu].to=to;
head[from]=jishu;
}
void tarjan(int now)
{
dfn[now]=low[now]=++cnt;
st[++top]=now;
vis[now]=;
for (int i=head[now];i;i=edge[i].next)
{
int to=edge[i].to;
if (!dfn[to]) tarjan(to),low[now]=min(low[now],low[to]);
else if (vis[to]) low[now]=min(low[now],dfn[to]);
}
if (dfn[now]==low[now])
{
tot++;
while(st[top+]!=now)
{
pos[st[top]]=tot;
sum[tot]+=val[st[top]];
vis[st[top--]]=;
}
}
}
void search(int x)
{
if (f[x]) return;
f[x]=sum[x];
int maxx=;
for (int i=head[x];i;i=edge[i].next)
{
int to=edge[i].to;
if (!f[to]) search(to);
maxx=max(maxx,f[to]);
}
f[x]+=maxx;
}
void clear()
{
jishu=;
memset(edge,,sizeof(edge));
memset(head,,sizeof(head));
}
int main()
{
n=read(),m=read();
for (int i=;i<=n;i++) val[i]=read();
for (int i=;i<=m;i++)
{
x[i]=read(),y[i]=read();
add(x[i],y[i]);
}
for (int i=;i<=n;i++) if (!dfn[i]) tarjan(i);
clear();
for (int i=;i<=m;i++) if (pos[x[i]]!=pos[y[i]]) add(pos[x[i]],pos[y[i]]);
for (int i=;i<=n;i++) search(i),ans=max(ans,f[i]);
printf("%d\n",ans);
return ;
}

另,如果是无向图缩点,一定要加上这句话:

if (edge[i].to==fa) continue;

【模板】割点

给定一个含有n个点m条边的无向图,求图的割点。

------------------------------------------

割点是指去掉这个点整个图便不连通的点。

我们可以同样用Tarjan算法,建立一颗搜索树。

如果此点为根节点,则判断是否有>=2棵子树。如果存在,那么此点为割点。

对于非根节点,如果low[v]>=dfn[u]($u\rightarrow v$)那么u点为割点(因为从u点开始无论怎么走都不可能回到原来的点了)。

思路还是比较清晰的,直接放代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=;
int head[],jishu;
int dfn[maxn],low[maxn],cnt;
int n,m,ans;
bool cut[maxn];
struct node
{
int next,to;
}edge[];
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-;ch=getchar();}
while(isdigit(ch)){x=x*+ch-'';ch=getchar();}
return x*f;
}
inline void add(int from,int to)
{
edge[++jishu].next=head[from];
edge[jishu].to=to;
head[from]=jishu;
}
void tarjan(int now,int fa)
{
dfn[now]=low[now]=++cnt;
int child=;
for (int i=head[now];i;i=edge[i].next)
{
int to=edge[i].to;
if (!dfn[to]){
tarjan(to,fa);
low[now]=min(low[now],low[to]);
if (low[to]>=dfn[now]&&now!=fa) cut[now]=;
if (now==fa) child++;
}
low[now]=min(low[now],dfn[to]);
}
if (child>=&&now==fa) cut[now]=;
}
int main()
{
n=read(),m=read();
for (int i=;i<=m;i++)
{
int u=read(),v=read();
add(u,v);add(v,u);
}
for (int i=;i<=n;i++) if (!dfn[i]) tarjan(i,i);
for (int i=;i<=n;i++) if (cut[i]) ans++;
printf("%d\n",ans);
for (int i=;i<=n;i++) if (cut[i]) printf("%d ",i);
return ;
}

最新文章

  1. Uva11374 Airport Express
  2. python mysql desc
  3. [算法导论]哈希表 @ Python
  4. 【jmeter】JMeter处理Cookie与Session
  5. beta冲刺6-咸鱼
  6. linux netlink通信机制
  7. Android深入四大组件(九)Content Provider的启动过程
  8. iOS 之 HTTPS集成实战应用
  9. 【BZOJ1821】[JSOI2010]部落划分(二分,并查集)
  10. [SQL]查询最新的数据
  11. sql语句查找某一列的值得最大值。
  12. Java调用SQL Server存储过程
  13. P4906 小奔关闹钟
  14. appium 遇到的坑
  15. Vue - 如何实现一个双向绑定
  16. 《metasploit渗透测试魔鬼训练营》学习笔记第三章----情报搜集
  17. 《Android传感器高级编程》
  18. bzoj 2321 数学
  19. 2017中南大学暑期集训day1 : debug&amp;STL-A
  20. 【leetcode 105. 从前序与中序遍历序列构造二叉树】解题报告

热门文章

  1. day60 django入门
  2. python 并发专题(七):Twisted相关函数以及实现
  3. 数据可视化之分析篇(二)Power BI 数据分析:客户购买频次分布
  4. tensorflow.python.framework.errors_impl.InvalidArgumentError: You must feed a value for placeholder tensor &#39;x_1&#39; with dtype float and shape [?,227,227,3]
  5. web前端知识点(webpack篇)
  6. HotSpot VM运行时
  7. python也能玩视频剪辑!moviepy操作记录总结
  8. OSCP Learning Notes - Capstone(2)
  9. P1776 宝物筛选
  10. STL源码剖析:仿函数