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
1 2
2 1
1 3
2 4
5 6
6 4
Sample Output
3
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 }
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!