(这次的图是自己画的2333) 世界真的很大 这道题有点扯,思路不太好想 关键是想清楚半连通分量的等价类 然后就好办了 有一些坑点 先看一下题吧 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
第一行包含3个整数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^8output
应包含两行,第一行包含一个整数K。第二行包含整数C Mod X.首先应该明确半连通分量是个什么东西 有向图,分量,自然先想到强连通分量 如果点u到达点v,点v不到达点u,点v所在的强连通分量u也全部可以到达,而全部不能到达v 如果能的话u和v就在一个强连通分量里了2333 即半连通分量就是强连通分量缩点后的一条链 即求缩点后的图里的最长链 可以看一下这篇 大体来说采用拓扑排序的思路 用bfs的方法更新状态 有个坑点就是两个强连通分量缩点后的点之间有可能不止一条边,可能会导致重复更新 对每一个点记录一下现在的点是由哪一个点更新来的,避免重复 没什么了 完整代码:
#include<stdio.h> #include<stack> #include<queue> #include<cstring> using namespace std; struct edge { int last,v,u; }ed[2000010],ad[2000010]; stack <int> stk; queue <int> state; int head[200010],place[200010],vis[200010],ins[200010]; int dfn[200010],low[200010],siz[200010],in[200010]; int dis[200010],nmb[200010]; int num=0,cnt=0,idx=0,mum=0,ans=0,bns=0,n,m,mod,tar; void add(int u,int v) { num++; ed[num].v=v; ed[num].u=u; ed[num].last=head[u]; head[u]=num; } void ade(int u,int v) { mum++; ad[mum].v=v; ad[mum].last=head[u]; head[u]=mum; } void tarjan(int u) { dfn[u]=low[u]=++idx; vis[u]=ins[u]=1; stk.push(u); for(int i=head[u];i;i=ed[i].last) { int v=ed[i].v; if(!vis[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if(ins[v]) { low[u]=min(low[u],dfn[v]); } } if(dfn[u]==low[u]) { cnt++;int t=-1; while(t!=u) { t=stk.top(); place[t]=cnt; siz[cnt]++; ins[t]=0; stk.pop(); } } } void rebuild() { memset(head,0,sizeof(head)); for(int i=1;i<=num;i++) if(place[ed[i].u]!=place[ed[i].v]) { ade(place[ed[i].u],place[ed[i].v]); in[place[ed[i].v]]++; } } void top() { memset(vis,0,sizeof(vis)); for(int i=1;i<=cnt;i++) if(in[i]==0) { state.push(i); dis[i]=siz[i];nmb[i]=1; } while(!state.empty()) { int u=state.front(); state.pop(); for(int i=head[u];i;i=ad[i].last) { int v=ad[i].v; in[v]--; if(in[v]==0) state.push(v); if(vis[v]==u) continue ; if(dis[v]<dis[u]+siz[v]) { dis[v]=dis[u]+siz[v]; nmb[v]=nmb[u]; } else if(dis[v]==dis[u]+siz[v]) nmb[v]=(nmb[u]+nmb[v])%mod; vis[v]=u; } } for(int i=1;i<=cnt;i++) if(dis[i]>ans) ans=dis[i]; for(int i=1;i<=cnt;i++) if(dis[i]==ans) bns=(bns+nmb[i])%mod; } 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]) tarjan(i); rebuild(); top(); printf("%d\n%d",ans,bns%mod); return 0; }嗯,就是这样