思路1
对于一个DAG,可以通过记忆化搜索得到答案。从每一个没有被访问过的点(即ans值为0)开始搜索,不断更新ans数组即可,如果搜到一个ans值不为0的点,那么直接用其ans值更新当前点的ans,不需要再搜一遍。
但是如果出现环,按照原先的搜索方式没法找到一个环中编号最大的点。因为在一个环中当第二次搜索到起点时,递归还没有返回过起点,所以起点的答案仍然没有被更新,也就是说此时这个环内编号最大的点并没有被维护到起点的ans中去。考虑通过缩点将原图转化为DAG,再按照DAG的思路求解。
据说对原图每个点直接dfs100遍也能过。
代码
#include <bits/stdc++.h>
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
using namespace std;
const int N=1E5+10,M=1E5+10;
int n,m,tot,timer,cnt;
int head[N],dfsn[N],fa[N],insta[N],ans[N],low[N],a[N];
stack<int> s;
struct Edge
{
int frm,to,nxt;
}e[M];
void add_edge(int u,int v)
{
e[++tot].nxt=head[u];e[tot].frm=u;e[tot].to=v;head[u]=tot;
}
inline int read()
{
int ret=0;char ch=getchar();
while(ch<'0' || ch>'9')
ch=getchar();
while(ch>='0' && ch<='9')
{
ret=ret*10+ch-'0';
ch=getchar();
}
return ret;
}
void tarjan(int u)
{
dfsn[u]=low[u]=++timer;
s.push(u);
insta[u]=1;
for(int i=head[u];i;i=e[i].nxt)
{
int v=e[i].to;
if(!dfsn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(insta[v] && dfsn[v]<low[u])
low[u]=dfsn[v];
}
if(low[u]==dfsn[u])
{
++cnt;
int cur;
do
{
cur=s.top();
s.pop();
insta[cur]=0;
fa[cur]=cnt;
a[cnt]=max(a[cnt],cur);
}
while(cur!=u);
}
}
void dfs(int u)
{
if(ans[u])
return;
ans[u]=a[u];
for(int i=head[u];i;i=e[i].nxt)
{
int v=e[i].to;
dfs(v);
ans[u]=max(ans[u],ans[v]);
}
}
int main()
{
// freopen("in.in","r",stdin);
n=read();m=read();
rep(i,1,m)
{
int u,v;
u=read();v=read();
add_edge(u,v);
}
rep(i,1,n)
{
if(!dfsn[i])
tarjan(i);
}
tot=0;
memset(head,0,sizeof(head));
rep(i,1,m)
{
int u=fa[e[i].frm],v=fa[e[i].to];
if(u==v)
continue;
add_edge(u,v);
}
rep(i,1,cnt)
{
if(!ans[i])
dfs(i);
}
rep(i,1,n)
printf("%d ",ans[fa[i]]);
printf("\n");
}
思路2
正难则反,反着做超级简单。考虑大的点反向能到达哪些点,反向建图,按照点编号从大到小dfs,就能保证每个点都能取到最优解。
代码
#include <bits/stdc++.h>
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
using namespace std;
const int N=1E5+10,M=N;
int n,m,tot;
int ans[N],head[N];
struct Edge
{
int nxt,to;
}e[M];
inline int read()
{
int ret=0;char ch=getchar();
while(ch<'0' || ch>'9')
ch=getchar();
while(ch>='0' && ch<='9')
{
ret=ret*10+ch-'0';
ch=getchar();
}
return ret;
}
inline void add_edge(int u,int v)
{
e[++tot].nxt=head[u];e[tot].to=v;head[u]=tot;
}
void dfs(int u,int fa)
{
if(ans[u])
return;
ans[u]=fa;
for(int i=head[u];i;i=e[i].nxt)
{
int v=e[i].to;
dfs(v,fa);
}
}
int main()
{
n=read();m=read();
rep(i,1,m)
{
int u,v;
u=read();v=read();
add_edge(v,u);
}
for(int i=n;i>0;--i)
{
dfs(i,i);
}
rep(i,1,n)
printf("%d ",ans[i]);
cout<<endl;
}