BZOJ1093 最大半连通子图

Description

  一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意
两点u,v,存在一条u到v的有向路径或者从v到u的有向路径。若G'=(V',E')满足V'?V,E'是E中所有跟V'有关的边,
则称G'是G的一个导出子图。若G'是G的导出子图,且G'半连通,则称G'为G的半连通子图。若G'是G所有半连通子图
中包含节点数最多的,则称G'是G的最大半连通子图。给定一个有向图G,请求出G的最大半连通子图拥有的节点数K
,以及不同的最大半连通子图的数目C。由于C可能比较大,仅要求输出C对X的余数。

Input

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

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
 
正解:tarjan+DP
解题报告:
  遥遥今天讲课讲了这道题,然后感觉这是最水的,就高兴地开了坑,调了半个晚上都没有发现为什么wa了。
  最后发现居然是有重边!!!!!!然后方案重复计算了,但我当时没有马上想出怎么判重,于是看了网上的题解发现可以用set,我真傻真的。
  做法其实挺简单,首先tarjan缩环,然后重构图,可以想到我们一定是在重构的图上选取一条链,使得链的点权和最大。DP可做。
 
 
  1 //It is made by jump~
  2 #include <iostream>
  3 #include <cstdlib>
  4 #include <cstring>
  5 #include <cstdio>
  6 #include <cmath>
  7 #include <algorithm>
  8 #include <ctime>
  9 #include <vector>
 10 #include <queue>
 11 #include <map>
 12 #include <set>
 13 #ifdef WIN32   
 14 #define OT "%I64d"
 15 #else
 16 #define OT "%lld"
 17 #endif
 18 using namespace std;
 19 typedef long long LL;
 20 const int MAXN = 100011;
 21 const int MAXM = 1000011;
 22 int MOD;
 23 int n,m,ecnt,ans,num;
 24 int first[MAXN],to[MAXM],next[MAXM];
 25 bool pd[MAXN];
 26 int dfn[MAXN],low[MAXN];
 27 int Stack[MAXN*2],top,belong[MAXN];
 28 int size[MAXN],cnt;
 29 int head[MAXN],ru[MAXN],f[MAXN];
 30 bool vis[MAXN];
 31 
 32 set<pair<int,int> >bst;//要有一个空格
 33 
 34 struct edge{
 35     int v,next;
 36 }e[MAXM];
 37 
 38 inline int getint()
 39 {
 40        int w=0,q=0;
 41        char c=getchar();
 42        while((c<'0' || c>'9') && c!='-') c=getchar();
 43        if (c=='-')  q=1, c=getchar();
 44        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
 45        return q ? -w : w;
 46 }
 47 
 48 inline void dfs(int x){
 49     dfn[x]=++ecnt; low[x]=dfn[x];
 50     pd[x]=1; Stack[++top]=x;
 51     for(int i=first[x];i;i=next[i]) {
 52     int v=to[i];
 53     if(!dfn[v]) { dfs(v); if(low[v]<low[x]) low[x]=low[v]; }
 54     else if(pd[v]) low[x]=min(low[v],low[x]);
 55     }
 56     if(dfn[x]==low[x]){
 57     cnt++; size[cnt]++; belong[x]=cnt; pd[x]=0;
 58     while(Stack[top]!=x&&top) belong[Stack[top]]=cnt,pd[Stack[top]]=0,top--,size[cnt]++;
 59     top--;
 60     }
 61 }
 62 
 63 inline void tarjan(){
 64     ecnt=0;
 65     for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i);
 66     ecnt=0;
 67     for(int i=1;i<=n;i++) {
 68     for(int j=first[i];j;j=next[j]) {
 69         int v=to[j];
 70         if(belong[i]!=belong[v]) {
 71         if(bst.find(make_pair(belong[i],belong[v]))!=bst.end()) continue;
 72         e[++ecnt].next=head[belong[i]]; head[belong[i]]=ecnt; e[ecnt].v=belong[v];
 73         ru[belong[v]]++;
 74         bst.insert(make_pair(belong[i],belong[v]));
 75         }
 76     }
 77     }
 78 }
 79 
 80 inline void DFS(int x){
 81     vis[x]=1;
 82     for(int i=head[x];i;i=e[i].next) {
 83     int v=e[i].v;
 84     if(!vis[v]) DFS(v);
 85     if(f[v]>f[x]) f[x]=f[v];
 86     }
 87     f[x]+=size[x];
 88 }
 89 
 90 inline void DFS2(int x){
 91     vis[x]=1;
 92     for(int i=head[x];i;i=e[i].next) {
 93     int v=e[i].v;
 94     if(!vis[v]) DFS2(v);
 95     //不能有重边!!!!!!
 96     if(f[x]==f[v]+size[x]) { dfn[x]+=dfn[v]; if(dfn[x]>=MOD) dfn[x]%=MOD; }
 97     }
 98     if(!head[x]) dfn[x]=1;
 99     if(f[x]==ans) { num+=dfn[x]; if(num>=MOD) num%=MOD; }
100 }
101 
102 inline void DP(){    
103     memset(vis,0,sizeof(vis));
104     for(int i=1;i<=cnt;i++) if(!ru[i]) DFS(i),ans=max(ans,f[i]);
105     memset(vis,0,sizeof(vis));  memset(dfn,0,sizeof(dfn));
106     for(int i=1;i<=cnt;i++) 
107     if(!ru[i]) {
108         DFS2(i);
109     }
110     printf("%d\n%d",ans,num);
111 }
112 
113 inline void work(){
114     n=getint(); m=getint(); MOD=getint();
115     int x,y;
116     for(int i=1;i<=m;i++) {
117     x=getint(); y=getint();
118     next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; 
119     }
120     tarjan();
121     DP();
122 }
123 
124 int main()
125 {
126   work();
127   return 0;
128 }

 

posted @ 2016-07-20 21:04  ljh_2000  阅读(361)  评论(0编辑  收藏  举报