首页 > 代码库 > P2456 - 膜拜神犇

P2456 - 膜拜神犇

P2456 - 膜拜神犇

Description

有一个 n 个点 m 条边的有向图, 蒟蒻可以从 1 号点出发在图上走, 并且最终需要回到 1 号点。 每个点都有一个神犇( 包括 1 号点), 每次经过一个没到过的点, 蒟蒻都会膜拜那位 神犇。 蒟蒻希望膜拜尽可能多的神犇。
由于蒟蒻膜拜神犇的欲望非常强烈, 所以他可以有一次机会逆着一条有向边的方向走。 ( 需要注意的是, 这条边的方向不会改变)。
你现在想知道, 蒟蒻最多能膜拜多少神犇?

Input

第一行 2 个整数 n、 m, 分别表示图的点数和边数。
第 2 行到底 m+1 行, 每行两个整数 u,v, 描述一条 u 到 v 的有向边。

Output

一行一个整数表示蒟蒻最多能膜拜多少神犇。

Sample Input

7 10
1 2
3 1
2 5
2 4
3 7
3 5
3 6
6 5
7 2
4 7

Sample Output

6

Hint

数据范围:
对于 25%的数据, 保证 n<=100, m<=250,
对于 45%的数据, 保证 n<=3,000, m<=7,000。
对于 100%的数据, 保证 n,m<=100,000。

Source

图论

 

尽可能拜访尽量多的神犇,所以强连通分量缩点,变成了DAG,接下来,不存在环了,只存在从一个点到达另外一个点,走一条反向边,最回到一点,因此能不能回到1点,也就是反图能不能从1点出发到达这个点;同时,dis要尽量的大,因此spfa求最大值,枚举所有的点,与这个点相连的所有的边,就可以了;

 

  1 /* QYP kuai wo dai ma*/
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<iomanip>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<cstdio>
  8 #include<queue>
  9 #include<ctime>
 10 #include<cmath>
 11 #include<stack>
 12 #include<map>
 13 #include<set>
 14 #define rep(i,a,b) for(register int i=a;i<=b;i++)
 15 #define ll long long
 16 #define re register
 17 using namespace std;
 18 const int N=100010;
 19 struct Edge{
 20     int to,net;
 21 }e1[N],e2[N],e[N];
 22 int h1[N],h2[N],num_e1,num_e2,n,m,num_e,head[N];
 23 int g[N],ans,a[N],b[N];
 24 inline int gi() {
 25     re int res=0;
 26     char ch=getchar();
 27     while(ch<0||ch>9) ch=getchar();
 28     while(ch>=0&&ch<=9) res=res*10+ch-0,ch=getchar();
 29     return res;
 30 }
 31 inline void add1(int x,int y) {
 32     e1[++num_e1].to=y,e1[num_e1].net=h1[x],h1[x]=num_e1;
 33 }
 34 inline void add2(int x,int y) {
 35     e2[++num_e2].to=y,e2[num_e2].net=h2[x],h2[x]=num_e2;
 36 }
 37 inline void add(int x,int y) {
 38     e[++num_e].to=y,e[num_e].net=head[x],head[x]=num_e;
 39 }
 40 int low[N],dfn[N],dfs_clock,sccno[N],scc_cnt;
 41 stack<int>S;
 42 void Tarjan(int x) {
 43     low[x]=dfn[x]=++dfs_clock;
 44     S.push(x);
 45     for(int i=head[x];i;i=e[i].net) {
 46         int to=e[i].to;
 47         if(!dfn[to]) {
 48             Tarjan(to);
 49             low[x]=min(low[x],low[to]);
 50         }
 51         else if(!sccno[to]) low[x]=min(low[x],dfn[to]);
 52     }
 53     if(low[x]==dfn[x]) {
 54         ++scc_cnt;
 55         int u;
 56         for(;;) {
 57             u=S.top();S.pop();
 58             sccno[u]=scc_cnt;
 59             g[scc_cnt]++;
 60             if(u==x) break;
 61         }
 62     }
 63 }
 64 void SUO() {
 65     rep(i,1,n) if(!dfn[i]) Tarjan(i);
 66     for(int x=1;x<=n;x++)
 67         for(int i=head[x];i;i=e[i].net) {
 68             int to=e[i].to;
 69             if(sccno[to]!=sccno[x]) {
 70                 add1(sccno[x],sccno[to]),add2(sccno[to],sccno[x]);
 71             }
 72         }
 73 }
 74 bool inq[N];
 75 void spfa(int ss,int hh[],Edge ee[],int dis[]) {
 76     memset(inq,0,sizeof(inq));
 77     queue<int>q;
 78     dis[ss]=g[ss];
 79     q.push(ss);inq[ss]=1;
 80     while(!q.empty()) {
 81         int u=q.front();q.pop();
 82         inq[u]=0;
 83         for(int i=hh[u];i;i=ee[i].net) {
 84             int to=ee[i].to;
 85             if(dis[to] < dis[u] + g[to]) {
 86                 dis[to]=dis[u]+g[to];
 87                 if(!inq[to]) q.push(to),inq[to]=1;
 88             }
 89         }
 90     }
 91 }
 92 int main() {
 93      freopen("OrzOrz.in","r",stdin);
 94     freopen("OrzOrz.out","w",stdout);
 95     n=gi(),m=gi();
 96     rep(i,1,m) {
 97         re int u=gi(),v=gi();
 98         add(u,v);
 99     }
100     SUO();
101     spfa(sccno[1],h1,e1,a);
102     spfa(sccno[1],h2,e2,b);
103     for(int x=1;x<=scc_cnt;x++) {
104         for(int i=h1[x];i;i=e1[i].net) {
105             int to=e1[i].to;
106             if(a[to]&&b[x]) ans=max(ans,a[to]+b[x]);
107         }
108     }
109     if(ans==g[sccno[1]])
110         printf("%d ",ans);
111     else 
112     printf("%d",ans-g[sccno[1]]);
113     return 0;
114 }

 

 

 

P2456 - 膜拜神犇