BZOJ 1093 [ZJOI2007]最大半连通子图

以前做过poj的一个判断图是否为弱连通的题,然后,这个题和poj那个差不多。

先强连通缩点,然后重新构图,然后找出包含点数最多的,统计个数即可,可以用拓扑排序搞~

pS:重新构图时有重边,然后导致统计方案数的重复。。wa了好久。。还是wzc神犇告诉我这个蒟蒻的。。

View Code
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstdlib>
  4 #include <cstring>
  5 #include <algorithm>
  6  
  7 #define N 200000
  8 #define M 5000000
  9 #define BUG system("pause")
 10  
 11 using namespace std;
 12  
 13 int head[N],to[M],next[M];
 14 int dfn[N],low[N];
 15 int st[M],ed[M];
 16 int n,m,cnt,ans,ansnum,mod;
 17 int divg,belong[N],t,p,stk[N],val[N];
 18 bool fg[N];
 19 int num[N],in[N],dp[N],q[M],vis[N];
 20  
 21 inline void add(int u,int v)
 22 {
 23     to[cnt]=v; next[cnt]=head[u]; head[u]=cnt++;
 24 }
 25  
 26 inline void read()
 27 {
 28     memset(head,-1,sizeof head); cnt=0;
 29     scanf("%d%d%d",&n,&m,&mod);
 30     for(int i=1;i<=m;i++)
 31     {
 32         scanf("%d%d",&st[i],&ed[i]);
 33         add(st[i],ed[i]);
 34     }
 35 }
 36  
 37 inline void dfs(int u)
 38 {
 39     low[u]=dfn[u]=++t;
 40     stk[++p]=u; fg[u]=true;
 41     for(int i=head[u];~i;i=next[i])
 42     {
 43         if(!dfn[to[i]])
 44         {
 45             dfs(to[i]);
 46             low[u]=min(low[u],low[to[i]]);
 47         }
 48         else if(fg[to[i]]) low[u]=min(low[u],dfn[to[i]]);
 49     }
 50     if(dfn[u]==low[u])
 51     {
 52         divg++;
 53         int tmp=-1;
 54         while(tmp!=u)
 55         {
 56             tmp=stk[p--];
 57             belong[tmp]=divg;
 58             val[divg]++;
 59             fg[tmp]=false;
 60         }
 61     }
 62 }
 63  
 64 inline void topsort()
 65 {
 66     int h=1,t=1,u;
 67     for(int i=1;i<=divg;i++)
 68         if(in[i]==0)
 69         {
 70             q[t++]=i;
 71             dp[i]=val[i];
 72             num[i]=1;
 73         }
 74     while(h<t)
 75     {
 76         u=q[h++];
 77         for(int i=head[u];~i;i=next[i])
 78         {
 79             in[to[i]]--;
 80             if(in[to[i]]==0) q[t++]=to[i];
 81             if(vis[to[i]]==u) continue;//有重边!! 
 82             if(dp[to[i]]<dp[u]+val[to[i]])
 83             {
 84                 dp[to[i]]=dp[u]+val[to[i]];
 85                 num[to[i]]=num[u];
 86             }
 87             else if(dp[to[i]]==dp[u]+val[to[i]])
 88             {
 89                 num[to[i]]=(num[to[i]]+num[u])%mod;
 90             }
 91             vis[to[i]]=u;
 92         }
 93     }
 94 }
 95  
 96 inline void go()
 97 {
 98     for(int i=1;i<=n;i++)
 99         if(!dfn[i]) dfs(i);
100     memset(head,-1,sizeof head); cnt=0;
101     for(int i=1;i<=m;i++)
102         if(belong[st[i]]!=belong[ed[i]])
103         {
104             add(belong[st[i]],belong[ed[i]]);
105             in[belong[ed[i]]]++;
106         }
107     topsort();
108     for(int i=1;i<=divg;i++)
109     {
110         if(dp[i]>ans)
111         {
112             ans=dp[i];
113             ansnum=num[i];
114         }
115         else if(dp[i]==ans) ansnum=(ansnum+num[i])%mod;
116     }
117     printf("%d\n%d\n",ans,ansnum);
118 }
119  
120 int main()
121 {
122     read();
123     go();
124     return 0;
125 }
原文地址:https://www.cnblogs.com/proverbs/p/2867089.html