轰炸---------------tarjan

题目描述

有 n 座城市,城市之间建立了 m 条有向的地下通道。你需要发起若干轮轰炸,每轮可以轰炸任意多个城市。但每次轰炸的城市中,不能存在两个不同的城市 i,j 满足可以通过地道从城市 i 到达城市 j。你需要求出最少需要多少轮可以对每座城市都进行至少一次轰炸。

输入数据

第一行两个整数 n,m。接下来 m 行每行两个整数 a,b 表示一条从 a 连向 b 的单向边。

输出数据

一行一个整数表示答案。

样例输入

5 4

1 2

2 3

3 1

4 5

样例输出

3

数据范围

对于 20%的数据,n,m≤10。

对于 40%的数据,n,m≤1000。

对于另外 30%的数据,保证无环。

对于 100%的数据,n,m≤1000000。

一句话题解:偏序集最小反链覆盖等于最长链。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,m,x,y,ans;
 4 int cnt,top,sum;
 5 int dfn[1000050];
 6 int low[1000050];
 7 int col[1000050];
 8 int siz[1000050];
 9 int du[1000050];
10 int t[1000050];
11 int f[1000050];
12 struct node
13 {
14     int tot;
15     int head[1000050];
16     int nex[1000050];
17     int ver[1000050];
18     void add(int x,int y)
19     {
20         nex[++tot]=head[x];
21         ver[tot]=y;
22         head[x]=tot;
23     }
24 }a,b;
25 void tarjan(int u)
26 {
27     dfn[u]=low[u]=++cnt;
28     t[++top]=u;
29     for(int i=a.head[u];i;i=a.nex[i])
30         if(!dfn[a.ver[i]])
31         {
32             tarjan(a.ver[i]);
33             low[u]=min(low[u],low[a.ver[i]]);
34         }
35         else if(!col[a.ver[i]])
36             low[u]=min(low[u],dfn[a.ver[i]]);
37     if(dfn[u]==low[u])
38     {
39         ++sum;
40         while(t[top+1]!=u)
41         {
42             col[t[top]]=sum;
43             ++siz[sum];
44             --top;
45         }
46     }
47 }
48 int main()
49 {
50     scanf("%d%d",&n,&m);
51     for(int i=1;i<=m;++i)
52     {
53         scanf("%d%d",&x,&y);
54         a.add(x,y);    
55     }
56     for(int i=1;i<=n;++i)
57         if(!dfn[i])
58             tarjan(i);
59     for(int i=1;i<=n;++i)
60         for(int j=a.head[i];j;j=a.nex[j])
61             if(col[i]!=col[a.ver[j]])
62             {
63                 ++du[col[a.ver[j]]];
64                 b.add(col[i],col[a.ver[j]]);
65             }
66     top=0;
67     for(int i=1;i<=sum;++i)
68         if(du[i]==0)
69             t[++top]=i;
70     while(top)
71     {
72         int now=t[top];
73         f[now]+=siz[now];
74         --top;    ans=max(ans,f[now]);
75         for(int i=b.head[now];i;i=b.nex[i])
76         {
77             f[b.ver[i]]=max(f[b.ver[i]],f[now]);
78             if(--du[b.ver[i]]==0)
79                 t[++top]=b.ver[i];
80         }
81     }
82     printf("%d",ans);
83     return 0;
84 }
View Code
原文地址:https://www.cnblogs.com/wyher/p/10362233.html