第一行包含两个整数N,M,X。N,M分别表示图G的点数与边数,X的意义如上文所述。接下来M行,每行两个正整数a, b,表示一条有向边(a, b)。图中的每个点将编号为1,2,3…N,保证输入中同一个(a,b)不会出现两次。
应包含两行,第一行包含一个整数K。第二行包含整数C Mod X.
对于100%的数据, N ≤100000, M ≤1000000;对于100%的数据, X ≤10^8。
【思路】
强连通分量+拓扑排序+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 }
bzoj 1093 [ZJOI2007]最大半连通子图(scc+DP)
原文:http://www.cnblogs.com/lidaxin/p/5103593.html