基本的想法就是对于每个点来一次bfs,求出它所能到达的点中最大的。这样是。
对于某个点,如果点能到达它,那么比
小的点都不必再搜。
于是可以想到一个优化:反向建边,点能到达点
即代表点
能
到达点。
基于上面的想法,只要从大往小搜,已经访问过的点不搜,即可保证答案的合法性。
(这是因为若之前访问过了,那么以前就已经带着比现在更优的信息(即源点编号),现在搜一定不会更优。)
#include<iostream> #include<cstdio> #include<queue> #define maxn 100010 int read(); using namespace std; queue<int>bfs; struct Edge{ int to,nt; }edge[maxn<<1];int tot,head[maxn]; void add(int a,int b){ edge[++tot].to=b; edge[tot].nt=head[a]; head[a]=tot; } int n,m; int vis[maxn]; int main(){ n=read(),m=read(); for(int i=1;i<=m;i++){ int x=read(),y=read(); add(y,x); } for(int k=n;k>=1;k--){//cout<<"i:"<<k<<endl; if(!vis[k]){ while(!bfs.empty()) bfs.pop(); bfs.push(k); while(!bfs.empty()){ int no=bfs.front();bfs.pop(); //cout<<no<<endl;cout<<"To:"; for(int i=head[no];i;i=edge[i].nt){ //cout<<edge[i].to<<' '; if(edge[i].to<k&&vis[edge[i].to]==0){ vis[edge[i].to]=k; bfs.push(edge[i].to); } }//cout<<endl; } } } for(int i=1;i<=n;i++)vis[i]=max(vis[i],i); for(int i=1;i<=n;i++)cout<<vis[i]<<' '; return 0; } int read(){ int s=0;char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();} return s; }