您的位置:首页 > 其它

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

2016-03-30 17:33 706 查看

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 }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: