식사 질문 후 오늘 브러시가, 갑자기 그런 문제가 자신의 작업 목록을보고, 쓰기를 열 것입니다.
표면 (N <= 10 ^ 5 m <= 10 ^ 5)는 DFS 생각 자연스러운는도 사용 벡터 메모리, I는 DFS 개의 방법을 생각 그래프를 트래버스하는 문제가 상기 :
모든 점 · DFS 있었다 각 지점의 경우, 각 시간 DFS 탐색을 달성 할 수 있으며, 최대 값이
방법은 매우 간단합니다, 매우 폭력적이지만, 문제는 각 포인트에 대한 최악의 경우 전체지도를 탐색 할 필요가 있다는 것입니다, 시간 복잡도 그것은이다 O (㎚)
· 최대 당신이 그것의 최대에이 점을 넣을 수없는 경우, 각 트래버스 점, DFS를 가리 키도록 첫째.
이 방법에 대한 최적화에 매우 큰 상대를 가지며, (A)의 값은 N, 난이 노드 각 액세스 포인트 시간을 각각의 액세스 포인트 (1)로부터 순환되고, (A)의 값이 가장 인 우수한 우리는 접합에 액세스 할 수있는 경우 다음 그 대답은 확실히 현재 큰 아니기 때문에. 이 방법의 시간 복잡도는 O (n 개에 + m) (바)는
코드를 구현 :
#include <cstdio>
#include <cctype>
#include <vector>
#define MAXN 100010
#define _for(i,a,b) for (int i = a;i <= b;i++)
#define _fd(i,a,b) for (int i = b;i >= a;i--)
using namespace std;
vector <int> G[MAXN];
int n,m,a[MAXN];
inline int read() {
int a = 0,f = 1;
char v= getchar();
while (!isdigit(v)) {
if (v == '-') {
f = -1;
}
v = getchar();
}
while (isdigit(v)) {
a = a * 10 + v - 48;
v = getchar();
}
return a * f;
}
inline void addedge(int u,int v) {
G[v].push_back(u);
}
void dfs(int x,int p) {
if (a[x]) {
return ;
}
a[x] = p;
int vv = G[x].size();
for (int i = 0;i < vv;i++) {
dfs(G[x][i],p);
}
}
int main() {
n = read(),m = read();
_for(i,1,m) {
int u = read(),v = read();
addedge(u,v);
}
_fd(i,1,n) {
dfs(i,i);
}
_for(i,1,n) {
printf("%d ",a[i]);
}
return 0;
}
나는이 문제에 대한 해결책을 볼 때 나중에 갑자기 Tarjan도 대답 할 수 발견!
Tarjan는 유니콤 구성 요소를 사용하여 얻은, 차이나 유니콤 (China Unicom) 내부의 각 구성 요소의 응답 점은 동일합니다!
코드 구현 (문제 해결)
#include<iostream>
2 #include<cstdio>
3 #include<algorithm>
4 #include<cstring>
5 using namespace std;
6
7 const int maxn = 10e5 + 5;
8
9 struct Edge{
10 int to,next;
11 }e[maxn];
12
13 int dfn[maxn],low[maxn],Time;
14 int s[maxn],top,vis[maxn];
15 int f[maxn],n,m;
16 int cnt,belong[maxn],MAX[maxn];
17 int k,x[maxn],y[maxn],head[maxn];
18
19 void add(int u,int v)
20 {
21 e[++k].to = v;
22 e[k].next = head[u];
23 head[u] = k;
24 }
25
26 void tarjan(int x) //求有向图强联通分量的tarjan,在这里不过多叙述,想学习的可以点链接去博客qwq
27 {
28 vis[x] = 1;
29 s[++top] = x;
30 dfn[x] = low[x] = ++Time;
31 for(int i = head[x];i;i=e[i].next)
32 {
33 int to = e[i].to;
34 if(!dfn[to])
35 {
36 tarjan(to);
37 low[x] = min(low[x],low[to]);
38 }
39 else if(vis[to])
40 low[x] = min(low[x],dfn[to]);
41 }
42 if(dfn[x] == low[x]) //如果x及其子树能够构成一个强联通分量
43 {
44 ++cnt;
45 int j;
46 while(j=s[top]) //将其子树中的点都加入此分量中,并将此分量中的最大值保存在MAX数组中
47 {
48 vis[j] = 0;
49 belong[j] = cnt;
50 MAX[cnt] = max(MAX[cnt],j);
51 top--;
52 if(j==x) break;
53 }
54 }
55 }
56
57 void dfs(int x) //记忆化搜索
58 {
59 if(f[x]) return;
60 f[x] = MAX[x]; //当前强联通分量中的最大值
61 for(int i=head[x];i;i=e[i].next)
62 {
63 int to = e[i].to;
64 if(!f[to]) dfs(to);
65 f[x] = max(f[x],f[to]); // 子树中的最大值
66 }
67 }
68
69 int main()
70 {
71 //freopen("data.in","r",stdin);
72 //freopen("jkb.out","w",stdout);
73 scanf("%d%d",&n,&m);
74 for(int i=1;i<=m;i++)
75 {
76 scanf("%d%d",&x[i],&y[i]); //保存边信息
77 add(x[i],y[i]);
78 }
79 for(int i=1;i<=n;i++) //求出强联通分量
80 if(!dfn[i])
81 tarjan(i);
82 memset(e,0,sizeof(e)); //清空原图
83 memset(head,0,sizeof(head));
84 k = 0;
85 for(int i=1;i<=m;i++) //建立新图
86 if(belong[x[i]]!=belong[y[i]])
87 add(belong[x[i]],belong[y[i]]);
88 for(int i=1;i<=cnt;i++)
89 if(!f[i]) dfs(i);
90 for(int i=1;i<=n;i++) //输出答案
91 printf("%d ",f[belong[i]]);
92 return 0;
93 }