题目描述
给出 NN 个点, MM 条边的有向图,对于每个点 vv ,求 A(v)A(v) 表示从点 vv 出发,能到达的编号最大的点。
输入格式:
第1 行,2 个整数 N,MN,M 。
接下来 MM 行,每行2个整数 Ui,ViUi,Vi ,表示边 (Ui,Vi)(Ui,Vi) 。点用 1,2,⋯,N1,2,⋯,N 编号。
输出格式:
N 个整数 A(1),A(2),⋯,A(N)A(1),A(2),⋯,A(N)
输入样例
4 3
1 2
2 4
4 3
样例输出
4 4 3 4
本题反向建边。题目问的是每个点能够到达的最大编号的点,反过来想就是反向建边后,从当前最大编号开始遍历(搜索),能达到哪些点,哪些点的答案就应该是当前最大编号的点。
#include <cstdio>
const int maxn = 100050;
using namespace std;
struct Point{
int to,nxt;
}e[maxn];
int cnt,ihead[maxn],vis[maxn];
void add(int x, int y){
e[++cnt].nxt = ihead[x];
e[cnt].to = y;
ihead[x] = cnt;
}
void dfs(int now, int st){
if(vis[now])
return;
vis[now]=st;
for(int i=ihead[now];i;i=e[i].nxt)
if(!vis[e[i].to])
dfs(e[i].to,st);
return;
}
int main(){
int n,m; //n个点,m条边。
scanf("%d%d",&n,&m);
for(int i=1; i<=m; ++i){
int x, y;
scanf("%d%d",&x,&y);
add(y,x);
}
for(int i=n; i; --i)
dfs(i, i);
for(int i=1;i<=n;++i)
printf("%d ",vis[i]);
return 0;
}
// 使用vector实现邻接表
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
#define MAXL 100010
int N, M, A[MAXL];
vector<int> G[MAXL]; //vector存图
void dfs(int x, int d) {
if(A[x]) return; //访问过
A[x] = d;
for(int i=0; i<G[x].size(); i++)
dfs(G[x][i], d);
}
int main() {
int u, v;
scanf("%d%d", &N, &M);
for(int i=1; i<=M; i++) {
scanf("%d%d", &u, &v);
G[v].push_back(u); //反向建边
}
for(int i=N; i; i--) dfs(i, i);
for(int i=1; i<=N; i++) printf("%d ", A[i]);
printf("\n");
return 0;
}