您的位置:首页 > 其它

BZOJ 1093 [ZJOI2007]最大半连通子图

2013-01-18 23:09 405 查看
以前做过poj的一个判断图是否为弱连通的题,然后,这个题和poj那个差不多。

先强连通缩点,然后重新构图,然后找出包含点数最多的,统计个数即可,可以用拓扑排序搞~

pS:重新构图时有重边,然后导致统计方案数的重复。。wa了好久。。还是wzc神犇告诉我这个蒟蒻的。。

View Code

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>

#define N 200000
#define M 5000000
#define BUG system("pause")

using namespace std;

int head
,to[M],next[M];
int dfn
,low
;
int st[M],ed[M];
int n,m,cnt,ans,ansnum,mod;
int divg,belong
,t,p,stk
,val
;
bool fg
;
int num
,in
,dp
,q[M],vis
;

inline void add(int u,int v)
{
to[cnt]=v; next[cnt]=head[u]; head[u]=cnt++;
}

inline void read()
{
memset(head,-1,sizeof head); cnt=0;
scanf("%d%d%d",&n,&m,&mod);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&st[i],&ed[i]);
add(st[i],ed[i]);
}
}

inline void dfs(int u)
{
low[u]=dfn[u]=++t;
stk[++p]=u; fg[u]=true;
for(int i=head[u];~i;i=next[i])
{
if(!dfn[to[i]])
{
dfs(to[i]);
low[u]=min(low[u],low[to[i]]);
}
else if(fg[to[i]]) low[u]=min(low[u],dfn[to[i]]);
}
if(dfn[u]==low[u])
{
divg++;
int tmp=-1;
while(tmp!=u)
{
tmp=stk[p--];
belong[tmp]=divg;
val[divg]++;
fg[tmp]=false;
}
}
}

inline void topsort()
{
int h=1,t=1,u;
for(int i=1;i<=divg;i++)
if(in[i]==0)
{
q[t++]=i;
dp[i]=val[i];
num[i]=1;
}
while(h<t)
{
u=q[h++];
for(int i=head[u];~i;i=next[i])
{
in[to[i]]--;
if(in[to[i]]==0) q[t++]=to[i];
if(vis[to[i]]==u) continue;//有重边!!
if(dp[to[i]]<dp[u]+val[to[i]])
{
dp[to[i]]=dp[u]+val[to[i]];
num[to[i]]=num[u];
}
else if(dp[to[i]]==dp[u]+val[to[i]])
{
num[to[i]]=(num[to[i]]+num[u])%mod;
}
vis[to[i]]=u;
}
}
}

inline void go()
{
for(int i=1;i<=n;i++)
if(!dfn[i]) dfs(i);
memset(head,-1,sizeof head); cnt=0;
for(int i=1;i<=m;i++)
if(belong[st[i]]!=belong[ed[i]])
{
add(belong[st[i]],belong[ed[i]]);
in[belong[ed[i]]]++;
}
topsort();
for(int i=1;i<=divg;i++)
{
if(dp[i]>ans)
{
ans=dp[i];
ansnum=num[i];
}
else if(dp[i]==ans) ansnum=(ansnum+num[i])%mod;
}
printf("%d\n%d\n",ans,ansnum);
}

int main()
{
read();
go();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: