题目:
团队链接:bomb
题面:
给定 n n n个点 m m m条边的有向图
现在每轮取走图上若干个点,每轮取点时会连带删掉一此点为出发点的所有边到达的点。(这句话我最后加上的,要不就要花里两个小时才能看懂这极其简易的题面,,)
要求每次删点不能存在两个不同的 点 i i i, j j j 使得可
以通过有向边从点 i i i到达点 j j j
求:最少多少次可以删完所有点
范围:
n
,
m
<
=
1
e
6
n,m<=1e6
n,m<=1e6
样例:
输入:
10 10
3 4
5 4
7 1
6 5
6 4
7 4
1 7
5 8
1 2
9 10
输出:
3
题解:
(这个题好不容易才参透的题面,花了我将进两个小时,还去询问了简化题目的老师,,,结果,,只说题解,,不说题意,,不唠了,上题解)
如果图中没有环的话,那答案就是最长链,但是,如果有环的话,就是tarjan求一下强连通分量然后转化成链就好,这样子转化,最后还是求最长链即可。
代码
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch<='9'&&ch>='0')s=s*10+ch-'0',ch=getchar();
return s*w;
}
const int sea=1e6+7;
struct see{int x,ver,edge,next;}e[sea];
vector<int>v[sea];
int n,m,tot,ans,st,cnt,deep,last[sea],id[sea],dfn[sea],low[sea],sta[sea],g[sea];
void add(int x,int y){e[++tot].ver=y;e[tot].next=last[x];last[x]=tot;}
void tarjan(int x)
{
dfn[x]=low[x]=++deep; sta[++st]=x;
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].ver;
if(!dfn[y]) tarjan(y),low[x]=min(low[y],low[x]);
else if(!id[y]) low[x]=min(low[x],dfn[y]);
}
if(dfn[x]==low[x])
{
id[x]=++cnt; v[cnt].push_back(x);
while(sta[st]^x) v[cnt].push_back(sta[st]),id[sta[st--]]=cnt;
--st;
}
}
int main()
{
n=read(); m=read();
for(int i=1;i<=m;i++)
{
int x,y;
x=read(); y=read(); add(x,y);
}
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
for(int x=1;x<=cnt;x++)
{
for(int j=0,u;j<v[x].size();j++)
{
for(int i=last[u=v[x][j]];i;i=e[i].next)
{
int y=e[i].ver;
if(id[y]^x) g[x]=max(g[id[y]],g[x]);
}
}
ans=max(ans,g[x]+=v[x].size());
}
printf("%d\n",ans);
return 0;
}