「
「
「图论
」
」
」第
4
4
4章 强连通分量
(
(
(前
2
2
2题
)
)
)
目录:
A.有向图缩点
B.受欢迎的牛
A
.
A.
A. 例题
1
1
1 有向图缩点![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/8c7bd18e1acd2998854e1a2e860f1c98.png)
分析:
t
a
r
j
a
n
tarjan
tarjan模板
建原图 然后
t
a
r
j
a
n
tarjan
tarjan求出所有强连通分量 然后建出
D
A
G
DAG
DAG
最后
d
p
dp
dp 在
D
A
G
DAG
DAG上求题目的
m
a
x
max
max
(
D
A
G
:
(DAG:
(DAG:有向无环图
D
i
r
e
c
t
e
d
Directed
Directed
A
c
y
c
l
i
c
Acyclic
Acyclic
G
r
a
p
h
)
Graph)
Graph)
CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<bitset>
//#pragma GCC optimize(2)
#define reg register
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
const int N=2e5+5;
int vis[N],dfn[N],low[N],Index;
int tot,con[N],sum[N],f[N],stack[N],top,edge,head[N];
struct node{
int to,next;
}a[N];
int n,m,value[N],x[N],y[N],ans;
void Clear()
{
memset(head,0,sizeof(head));
memset(a,0,sizeof(a));
edge=0;
}
void add(int x,int y)
{
a[++edge]=(node){y,head[x]};
head[x]=edge;
}
void tarjan(int x)
{
stack[++top]=x; //手写栈
vis[x]=1;
dfn[x]=low[x]=++Index;
for(int i=head[x];i;i=a[i].next)
{
int qwq=a[i].to;
if(!dfn[qwq])
{
tarjan(qwq);
low[x]=min(low[x],low[qwq]);
}else if(vis[qwq])
low[x]=min(low[x],dfn[qwq]);
}
if(dfn[x]==low[x])
{
tot++;
while(stack[top+1]!=x)
{
con[stack[top]]=tot;
sum[tot]+=value[stack[top]];
vis[stack[top--]]=0;
}
}
}
void dfs(int x)
{
if(f[x]) return;
f[x]=sum[x];
int res=0;
for(int i=head[x];i;i=a[i].next)
{
if(!f[a[i].to]) dfs(a[i].to);
res=max(res,f[a[i].to]); //在DAG上求最大值
}
f[x]+=res;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&value[i]);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x[i],&y[i]);
add(x[i],y[i]);
}
for(int i=1;i<=n;i++)
if(!dfn[i]) tarjan(i);
Clear();
for(int i=1;i<=m;i++)
if(con[x[i]]!=con[y[i]])
add(con[x[i]],con[y[i]]);
for(int i=1;i<=tot;i++)
if(!f[i]){
dfs(i);
ans=max(ans,f[i]);
}
printf("%d",ans);
return 0;
}
B . B. B. 例题 2 2 2 受欢迎的牛
分析:
一个很水的
d
f
s
dfs
dfs 可过
Y
b
t
Ybt
Ybt数据:
l
i
n
k
link
link
t
a
r
j
a
n
:
tarjan:
tarjan:
完成缩点后 会得到一张
D
A
G
DAG
DAG
这时候找到一个出度为
0
0
0的强连通分量 说明这里面的所有牛 都是最受欢迎的 就可以输出它的大小了
因为是有向无环 所以如果被所有牛仰慕 自己又仰慕别的牛 就说明还存在环
CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<bitset>
//#pragma GCC optimize(2)
#define reg register
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
const int N=1e6+5;
int tot,flag,dnf[N],low[N],head[N],stack[N],value[N],Index,ans[N],con[N],size,len;
struct node{
int to,next;
}a[N];
int n,m,place,top;
bool f[N],in[N];
void add(int x,int y)
{
a[++tot]=(node){y,head[x]};
head[x]=tot;
}
int find()
{
int res=0;
for(int i=1;i<=size;i++)
for(int j=head[value[i]];j;j=a[j].next)
if(!in[a[j].to]) res++;
return res;
}
void tarjan(int x)
{
dnf[x]=low[x]=++Index;
stack[++top]=x;
f[x]=1;
for(int i=head[x];i;i=a[i].next)
{
int qwq=a[i].to;
if(!dnf[qwq])
{
tarjan(qwq);
low[x]=min(low[x],low[qwq]);
}else if(f[qwq]) low[x]=min(low[x],dnf[qwq]);
}
if(dnf[x]==low[x])
{
int qwq;
len++;
while(qwq!=x)
{
qwq=stack[top--];
f[qwq]=0;
value[++size]=qwq;
in[qwq]=1;
ans[len]++; //强连通分量大小
}
con[len]=find();
size=0;
memset(in,0,sizeof(in));
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
}
for(int i=1;i<=n;i++)
if(!dnf[i]) tarjan(i);
for(int i=1;i<=len;i++)
if(!con[i]){
flag++;
place=i;
}
if(flag==1) printf("%d",ans[place]);
else printf("0");
return 0;
}