zoukankan      html  css  js  c++  java
  • [bzoj1093] [ZJOI2007] 最大半连通子图

    Description

    一个有向图 (G=(V,E)) 称为半连通的((Semi-Connected)),如果满足:$ forall u,v in V$,满足 (u→v)(v→u),即对于图中任意两点 (u)(v) ,存在一条 (u)(v) 的有向路径或者从 (v)(u) 的有向路径。若 (G'=(V',E')) 满足 (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 leq 100000),$ M leq 1000000$;对于 (100 \%) 的数据, (X leq 10^8)

    Output

    应包含两行,第一行包含一个整数 (K) 。第二行包含整数 $ C$ (Mod) (X).

    Sample Input

    6 6 20070603

    1 2

    2 1

    1 3

    2 4

    5 6

    6 4

    Sample Output

    3
    3


    题解

    一道不错的题。
    “半连通子图”看上去有些棘手,那先 (tarjan) 缩环,把原先的有向图变成 (DAG)
    然后稍微推一下会发现,半连通子图相当于 (DAG) 中的一条链,我们要求的就是 (DAG) 中的最长链及其个数
    (dp) 一下就好了。


    代码

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    
    using namespace std;
    
    const int N = 100005;
    
    struct node{
    	int v;
    	node *next;
    }pool[N*10],*h[N],pool2[N*10],*h2[N];
    int cnt,cnt2;
    void addedge(int u,int v){
    	node *p=&pool[++cnt];
    	p->v=v;p->next=h[u];h[u]=p;
    }
    
    int n,m,X;
    int dfn[N],low[N],tot,vis[N];
    int st[N],top,scc[N],sccno,size[N];
    void dfs(int u){
    	int v;
    	dfn[u]=low[u]=++tot;
    	st[top++]=u;
    	vis[u]=1;
    	for(node *p=h[u];p;p=p->next)
    		if(!vis[v=p->v]){
    			dfs(v);
    			low[u]=min(low[u],low[v]);
    		}
    		else if(vis[v]==1) low[u]=min(low[u],dfn[v]);
    	if(low[u]==dfn[u]){
    		sccno++; 
    		for(;;){
    			size[sccno]++;
    			vis[v=st[--top]]=2;
    			scc[v]=sccno;
    			if(u==v) break;
    		}
    	}
    }
    
    struct edge{
    	int u,v;
    	bool operator < (const edge &b) const{
    		if(scc[u]!=scc[b.u]) return scc[u]<scc[b.u];
    		return scc[v]<scc[b.v];
    	}
    }ed[N*10];
    void addedge2(int u,int v){
    	node *p=&pool2[++cnt2];
    	p->v=v;p->next=h2[u];h2[u]=p;
    }
    int ml[N],mt[N];
    void dp(int u){
    	if(ml[u]!=-1) return;
    	int v;
    	ml[u]=size[u]; mt[u]=1;
    	for(node *p=h2[u];p;p=p->next){
    		dp(v=p->v);
    		if(ml[u]<ml[v]+size[u]) ml[u]=ml[v]+size[u],mt[u]=mt[v];
    		else if(ml[u]==ml[v]+size[u]) mt[u]=(mt[u]+mt[v])%X;
    	}
    }
    
    int main()
    {
    	scanf("%d%d%d",&n,&m,&X);
    	for(int i=0;i<m;i++) 
    		scanf("%d%d",&ed[i].u,&ed[i].v),addedge(ed[i].u,ed[i].v);
    	
    	for(int i=1;i<=n;i++)
    		if(!dfn[i]) dfs(i);
    	sort(ed,ed+m);
    	for(int i=0;i<m;i++){
    		if(i!=0 && scc[ed[i].u]==scc[ed[i-1].u] && scc[ed[i].v]==scc[ed[i-1].v])
    			continue;
    		if(scc[ed[i].u]==scc[ed[i].v]) continue;
    		addedge2(scc[ed[i].u],scc[ed[i].v]);
    	}
    	
    	memset(ml,-1,sizeof(ml));
    	for(int i=1;i<=n;i++)
    		if(ml[i]==-1) dp(i);
    		
    	int ans=0,t=0;
    	for(int i=1;i<=n;i++)
    		if(ml[i]>ans) ans=ml[i],t=mt[i];
    		else if(ml[i]==ans) t=(t+mt[i])%X;
    	printf("%d
    %d
    ",ans,t); 
    	
    	return 0;
    }
    
    既然选择了远方,便只顾风雨兼程
  • 相关阅读:
    Source Insight 安装使用
    size_t和ssize_t
    jquery ui autoComplete自动完成
    一个php类 Autoloader
    php register_shutdown_function
    mysql concat和group_concat
    nginx反向代理
    6.关于QT中的内存管理,动态的制作,动态库的调用,静态库的制作
    Sublime Text2 按shift键选择不了的问题
    javascript--瀑布流
  • 原文地址:https://www.cnblogs.com/lindalee/p/9852373.html
Copyright © 2011-2022 走看看