山东济南彤昌机械科技有限公司 山东济南江鹏工贸游有限公司

bzoj 1093 [ZJOI2007]最大半连通子图(scc+DP)

 

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

Time Limit: 30 Sec  Memory Limit: 162 MB
Submit: 2286  Solved: 897
[Submit][Status][Discuss]

Description

Input

第一行包含两个整数N,M,X。N,M分别表示图G的点数与边数,X的意义如上文所述。接下来M行,每行两个正整数a, b,表示一条有向边(a, b)。图中的每个点将编号为1,2,3…N,保证输入中同一个(a,b)不会出现两次。

Output

应包含两行,第一行包含一个整数K。第二行包含整数C Mod X.

Sample Input

6 6 20070603
1 2
2 1
1 3
2 4
5 6
6 4

Sample Output

3
3

HINT

对于100%的数据, N ≤100000, M ≤1000000;对于100%的数据, X ≤10^8。

Source

 

 

【思路】

       强连通分量+拓扑排序+DP

       求scc,锁点。则问题转化为求DAG上的最长路,在拓扑序上进行DP即可。 

    需要注意的是重新构图的时候会有重边,为了防止重复计数需要特别处理一下。

 

【代码】

  1 #include<cstdio>
  2 #include<stack>
  3 #include<queue>
  4 #include<vector>
  5 #include<cstring>
  6 #include<iostream>
  7 using namespace std;
  8 
  9 const int maxn =  100000+10;
 10 
 11 vector<int> g[maxn],G[maxn];
 12 int pre[maxn],lowlink[maxn],sccno[maxn],scccnt,dfsclock;
 13 stack<int> S;
 14 
 15 int dfs(int u) {
 16     pre[u]=lowlink[u]=++dfsclock;
 17     S.push(u);
 18     for(int i=0;i<g[u].size();i++) {
 19         int v=g[u][i];
 20         if(!pre[v]) {
 21             dfs(v);
 22             lowlink[u]=min(lowlink[u],lowlink[v]);
 23         }
 24         else if(!sccno[v]) {
 25             lowlink[u]=min(lowlink[u],pre[v]);
 26         }
 27     }
 28     if(lowlink[u]==pre[u]) {
 29         ++scccnt;
 30         for(;;) {
 31             int x=S.top() ; S.pop();
 32             sccno[x]=scccnt;
 33             if(x==u) break;
 34         }
 35     }
 36 }
 37 void findscc(int n) {
 38     memset(pre,0,sizeof(pre));
 39     memset(sccno,0,sizeof(sccno));
 40     dfsclock=scccnt=0;
 41     for(int i=0;i<n;i++)
 42         if(!pre[i]) dfs(i);
 43 }
 44 
 45 int n,m,MOD;
 46 int d[maxn],cnt[maxn];
 47 
 48 int val[maxn],in[maxn];
 49 void build() {
 50     for(int i=0;i<n;i++) {
 51         val[sccno[i]]++;
 52         for(int j=0;j<g[i].size();j++) {
 53             int v=g[i][j];   
 54             if(sccno[i]==sccno[v]) continue;
 55             in[sccno[v]]++;
 56             G[sccno[i]].push_back(sccno[v]);
 57         }
 58     }
 59 }
 60 void solve() {
 61     queue<int> q;
 62     int vis[maxn];
 63     for(int i=1;i<=scccnt;i++) if(!in[i]) {
 64         d[i]=val[i] , cnt[i]=1;
 65         q.push(i);
 66     }
 67     while(!q.empty()) {
 68         int u=q.front(); q.pop();
 69         for(int i=0;i<G[u].size();i++) {
 70             int v=G[u][i];
 71             if(!(--in[v])) q.push(v);
 72             if(vis[v]!=u) {                        //重新构图后有重边 防止重复计数 
 73                 if(d[v]<d[u]+val[v]) {
 74                     d[v]=d[u]+val[v]; cnt[v]=cnt[u];
 75                 }
 76                 else if(d[v]==d[u]+val[v])
 77                     cnt[v]=(cnt[v]+cnt[u])%MOD;
 78             }
 79             vis[v]=u;
 80         }
 81     }
 82 }
 83 
 84 int main() {
 85     scanf("%d%d%d",&n,&m,&MOD);
 86     int u,v;
 87     while(m--) {
 88         scanf("%d%d",&u,&v);
 89         u-- , v--;
 90         g[u].push_back(v);
 91     }
 92     findscc(n);
 93     build();
 94     solve();
 95     int ans=0,ansnum=0;
 96     for(int i=1;i<=scccnt;i++)
 97         if(ans<d[i])  ans=d[i] , ansnum=cnt[i];
 98         else if(ans==d[i]) ansnum=(ansnum+cnt[i])%MOD;
 99     printf("%d\n%d",ans,ansnum);
100     return 0;
101 }

 

posted on 2016-01-05 19:42  hahalidaxin  阅读(257)  评论(0编辑  收藏  举报