bzoj 1093: [ZJOI2007]最大半连通子图
Posted 一蓑烟雨任生平
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 1093: [ZJOI2007]最大半连通子图相关的知识,希望对你有一定的参考价值。
1093: [ZJOI2007]最大半连通子图
Time Limit: 30 Sec Memory Limit: 162 MBSubmit: 3512 Solved: 1391
[Submit][Status][Discuss]
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
HINT
Source
思路:tarjin缩点+拓扑排序+dp
错因:
1.tarjin错误,两个low值取小,取错了。
2.弱智错误:比较时else少写了判断。
#include<iostream> #include<map> #include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define MAXN 1000001 using namespace std; queue<int>que; map<int,int>ma[MAXN]; int col[MAXN],sum[MAXN]; int sumcol,maxn=-1,num,cnt; int n,m,tot,mod,tim,top,tot1; int into[MAXN],f[MAXN],ans[MAXN]; int to[MAXN],net[MAXN],head[MAXN]; int to1[MAXN],net1[MAXN],head1[MAXN]; int low[MAXN],dfn[MAXN],vis[MAXN],stack[MAXN],visstack[MAXN]; void add(int u,int v){ to[++tot]=v;net[tot]=head[u];head[u]=tot; } void add1(int u,int v){ to1[++tot1]=v;net1[tot1]=head1[u];head1[u]=tot1; } void tarjin(int now){ low[now]=dfn[now]=++tim; stack[++top]=now; vis[now]=1; visstack[now]=1; for(int i=head[now];i;i=net[i]) if(visstack[to[i]]) low[now]=min(low[now],dfn[to[i]]); else if(!vis[to[i]]){ tarjin(to[i]); low[now]=min(low[now],low[to[i]]); } if(low[now]==dfn[now]){ sumcol++; col[now]=sumcol; while(stack[top]!=now){ col[stack[top]]=sumcol; visstack[stack[top]]=0; top--; } visstack[now]=0; top--; } } int main(){ scanf("%d%d%d",&n,&m,&mod); for(int i=1;i<=m;i++){ int u,v; scanf("%d%d",&u,&v); add(u,v); } for(int i=1;i<=n;i++) if(!vis[i]) tarjin(i); for(int i=1;i<=n;i++) sum[col[i]]++; for(int i=1;i<=n;i++) for(int j=head[i];j;j=net[j]) if(col[i]!=col[to[j]]){ if(ma[col[i]].find(col[to[j]])==ma[col[i]].end()){ ma[col[i]][col[to[j]]]=true; add1(col[i],col[to[j]]); into[col[to[j]]]++; } } memset(vis,0,sizeof(vis)); while(!que.empty()) que.pop(); for(int i=1;i<=sumcol;i++) if(into[i]==0){ que.push(i); ans[i]=1; } while(!que.empty()){ int now=que.front(); que.pop(); f[now]+=sum[now]; ++cnt; for(int i=head1[now];i;i=net1[i]){ into[to1[i]]--; if(vis[to1[i]]!=cnt){ if(f[to1[i]]<f[now]){ f[to1[i]]=f[now]; ans[to1[i]]=ans[now]; } else if(f[to1[i]]==f[now]){ ans[to1[i]]=(ans[to1[i]]+ans[now])%mod; vis[to1[i]]=cnt; } } if(!into[to1[i]]) que.push(to1[i]); } } for(int i=1;i<=sumcol;i++) if(f[i]>maxn){ maxn=f[i]; num=ans[i]; } else if(f[i]==maxn) num=(num+ans[i])%mod; cout<<maxn<<endl<<num; } /* 17 22 1234567 3 12 10 17 2 12 6 15 8 16 7 13 9 16 14 9 5 16 5 11 8 3 1 7 12 1 9 4 13 3 9 17 17 6 11 14 15 10 4 5 8 17 8 1 */
以上是关于bzoj 1093: [ZJOI2007]最大半连通子图的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ1093ZJOI2007最大半联通子图 [拓扑][DP][Tarjan]