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

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

    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

    Sample Output

    3
    3

      这是一道水题无疑。但是,所谓的半连通确实很能混淆视听。既然题目只针对所谓的“最大半连通子图”,那就依它来吧。
      很明显强连通满足半联通的条件。然后再想,不在同一个强连通分量中,怎样才能做到所谓的“半连通”?
      可能你已经明白了。实在是太简单不过了。找DAG(人称“大哥”)上的一条链足矣。
      而“最大半连通子图拥有的节点数”,即是找缩点后DAG图中拥有最多节点的链。注意,此处并不是找最长链。
      另外,计数?简单。按拓扑序更新即是了。
      但是,但是,但是!
      我第一次交上去WA了。因为,图中有重边。DP更新方案数时很有可能重复计数。
      代码如下:
     1 /**************************************************************
     2     Problem: 1093
     3     User: Doggu
     4     Language: C++
     5     Result: Accepted
     6     Time:1360 ms
     7     Memory:23928 kb
     8 ****************************************************************/
     9  
    10 #include <cstdio>
    11 #include <cstring>
    12 #include <algorithm>
    13  
    14 template<class T>inline void readin(T &res) {
    15     static char ch;T flag=1;
    16     while((ch=getchar())<'0'||ch>'9')if(ch=='-')flag=-1;
    17     res=ch-48;while((ch=getchar())>='0'&&ch<='9')res=(res<<1)+(res<<3)+ch-48;res*=flag;
    18 }
    19  
    20 const int N = 100100;
    21 const int M = 1001000;
    22 struct Edge {int v,upre;};
    23 struct CON {
    24     Edge e[M];int head[N], ne;
    25     void clear(int p) {ne=p;memset(head,p,sizeof(head));}
    26     inline void adde(int u,int v) {e[++ne]=(Edge){v,head[u]};head[u]=ne;}
    27 }g,ng;
    28  
    29 int n, m, MOD, u, v;
    30 int dfn[N], low[N], idy, stack[N], top, col[N], tcol;
    31 int siz[N], f[N], t[N], in[N], vis[N];
    32 bool ins[N];
    33 void tarjan(int u) {
    34     dfn[u]=low[u]=++idy;
    35     stack[++top]=u;ins[u]=1;
    36     for( int i = g.head[u]; i; i = g.e[i].upre ) {
    37         int v=g.e[i].v;
    38         if(!dfn[v]) tarjan(v), low[u]=std::min(low[u],low[v]);
    39         else if(ins[v]) low[u]=std::min(low[u],dfn[v]);
    40     }
    41     if(low[u]==dfn[u]) {
    42         ++tcol;
    43         while(stack[top+1]!=u) {
    44             col[stack[top]]=tcol;
    45             siz[tcol]++;
    46             ins[stack[top--]]=0;
    47         }
    48     }
    49 }
    50 inline void add(int &a,int b) {a=a+b>MOD?a+b-MOD:a+b;}
    51 int main() {
    52     readin(n);readin(m);readin(MOD);
    53     g.clear(0);ng.clear(0);
    54     for( int i = 1; i <= m; i++ ) {
    55         readin(u);readin(v);
    56         g.adde(u,v);
    57     }
    58     for( int i = 1; i <= n; i++ ) if(!dfn[i]) tarjan(i);
    59     for( int u = 1; u <= n; u++ ) for( int i = g.head[u]; i; i=g.e[i].upre ) {
    60         int v=g.e[i].v;
    61         if(col[u]!=col[v]) ng.adde(col[u],col[v]), in[col[v]]++;
    62     }
    63     top=0;
    64     for( int i = 1; i <= tcol; i++ ) if(!in[i]) stack[++top]=i,  f[i]=siz[i], t[i]=1;
    65     while(top) {
    66         int u=stack[top];top--;
    67         for( int i = ng.head[u]; i; i = ng.e[i].upre ) {
    68             int v=ng.e[i].v;
    69             in[v]--;
    70             if(!in[v]) stack[++top]=v;
    71             if(vis[v]==u) continue;
    72             if(f[u]+siz[v]>f[v]) f[v]=f[u]+siz[v], t[v]=t[u];
    73             else if(f[u]+siz[v]==f[v]) add(t[v],t[u]);
    74             vis[v]=u;
    75         }
    76     }
    77     int num=0, ans=0;
    78     for( int i = 1; i <= tcol; i++ ) num=std::max(num,f[i]);
    79     printf("%d
    ",num);
    80     for( int i = 1; i <= tcol; i++ ) if(f[i]==num) add(ans,t[i]);
    81     printf("%d
    ",ans);
    82     return 0;
    83 }
    84 
    tarjan缩点+拓扑排序简单DP
  • 相关阅读:
    C++中的静态数据成员的作用与好处
    C++中的虚函数表
    CF292-D
    CF292-C
    CF292-B
    CF292-A
    CF291-B
    CF291-C
    CF287-B
    CF287-C
  • 原文地址:https://www.cnblogs.com/Doggu/p/bzoj1093.html
Copyright © 2011-2022 走看看