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

来源:互联网 发布:微信淘宝链接怎么打开 编辑:程序博客网 时间:2024/04/29 14:56

最大半连通子图

【问题描述】

一个有向图称为半连通的(Semi-Connected),如果满足:

,即对于图中任意两点u,v,存在一条uv的有向路径或者从vu的有向路径。

      

       若满足,则称G’是G的一个导出子图。

       若G’G的导出子图,且G’半连通,则称G’G的半连通子图。

       若G’G所有半连通子图中包含节点数最多的,则称G’G的最大半连通子图。

      

       给定一个有向图G,请求出G的最大半连通子图拥有的节点数K,以及不同的最大半连通子图的数目C。由于C可能比较大,仅要求输出CX的余数。

【输入文件】

       输入文件semi.in第一行包含两个整数NMXNM分别表示图G的点数与边数,X的意义如上文所述。接下来M行,每行两个正整数a,b,表示一条有向边(a, b)。图中的每个点将编号为1,2,3…N,保证输入中同一个(a,b)不会出现两次。

【输出文件】

       输出文件semi.out应包含两行,第一行包含一个整数K。第二行包含整数C Mod X.

【样例输入】

       6 6 20070603

1 2

2 1

1 3

2 4

5 6

6 4

【样例输出】

       3

       3

【数据规模】

       对于20%的数据,   N ≤18;

       对于60%的数据,   N ≤10000;

       对于100%的数据, N ≤100000, M ≤1000000;

    对于100%的数据, X ≤108


题解:缩点。之后发现最大半连通一定是一条单向最长链,所以拓扑dp。

#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
int n,m;
LL mod;
struct node
{
int x,y,next;
}a[1110000],b[1110000];int lena,lasta[110000],lenb,lastb[110000];
void insa(int x,int y)
{
lena++;a[lena].x=x;a[lena].y=y;
a[lena].next=lasta[x];lasta[x]=lena;
}
int ru[110000];
void insb(int x,int y)
{
lenb++;b[lenb].x=x;b[lenb].y=y;
b[lenb].next=lastb[x];lastb[x]=lenb;
ru[y]++;
}
int dfn[110000],low[110000],belong[110000],num[110000],id,cnt;
int sta[110000],tp;
bool insta[110000];
int mymin(int x,int y){ return x>y?y:x; }
void dfs(int x)
{
dfn[x]=low[x]=++id;sta[++tp]=x;insta[x]=true;
for(int k=lasta[x];k;k=a[k].next)
{
int y=a[k].y;
if(dfn[y]==-1)
{
dfs(y);
low[x]=mymin(low[x],low[y]);
}
else
{
if(insta[y]) low[x]=mymin(low[x],dfn[y]);
}
}
if(low[x]==dfn[x])
{
int i=0;cnt++;
while(i!=x)
{
i=sta[tp--];insta[i]=false;
belong[i]=cnt;
num[cnt]++;
}
}
}
void rebuilt()
{
memset(ru,0,sizeof(ru));
lenb=0;memset(lastb,0,sizeof(lastb));
for(int i=1;i<=lena;i++)
if( belong[ a[i].x ]!= belong[a[i].y])
insb( belong[ a[i].x ],belong[a[i].y]);
}
int q[110000],f[110000],g[110000],from[110000];
int main()
{
//freopen("semi","r",stdin);freopen("semi","w",stdout);
scanf("%d%d%lld",&n,&m,&mod);
lena=0;memset(lasta,0,sizeof(lasta));
for(int i=1;i<=m;i++)
{
int x,y;scanf("%d%d",&x,&y);
insa(x,y);
}
memset(num,0,sizeof(num));
memset(dfn,-1,sizeof(dfn));
memset(low,-1,sizeof(low));
memset(insta,false,sizeof(insta));
id=tp=cnt=0;
for(int i=1;i<=n;i++)
{
if(dfn[i]==-1) dfs(i);
}
rebuilt();
int head,tail=0;
for(int i=1;i<=cnt;i++)
{
if(ru[i]==0) q[++tail]=i;
f[i]=num[i];g[i]=1;
}
head=1;
while(head<=tail)
{
int x=q[head++];
for(int k=lastb[x];k;k=b[k].next)
{
int y=b[k].y;
ru[y]--;
if(ru[y]==0)q[++tail]=y;
if(from[y]==x) continue;
if(f[x]+num[y]>f[y])
{
f[y]=f[x]+num[y];
g[y]=g[x];
}
else if(f[x]+num[y]==f[y])
g[y]=(g[y]+g[x])%mod;
from[y]=x;
}
}
int mx=0,ans=0;

for(int i=1;i<=cnt;i++)
{
if( f[i]>mx)mx=f[i],ans=g[i];
else if(f[i]==mx)ans=(ans+g[i])%mod;
}
printf("%d\n%d\n",mx,ans);
return 0;
}

1 0
原创粉丝点击