zoukankan      html  css  js  c++  java
  • BZOJ 1093 最大半连通子图 题解

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

    Time Limit: 30 Sec  Memory Limit: 162 MB
    Submit: 2767  Solved: 1095
    [Submit][Status][Discuss]

    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

    HINT

     

    Source

    ——————————————————我是分割线————————————————————
    spfa+dp+tarjan

    先缩点,重新建图,使其成为一个 DAG,

    DAG 中每个点有一个点权表示这个点是原图中的几个点缩成的

    新图中的一个最大半连通子图,必然是新图中的一个最长链(点权和最大),

    知道了这点之后,DP 就行了,

    类似于树形 DP,先求出从每个点出发,能走的最长链是多长,统计最长的那条就是最大半连通子图的点的数量了,

    至于怎么求有多少个最大半连通子图,也是一样的 DP 就行,在上一步的 DP 之后,再 DP 一遍,统计每个点出发能走出多少条最长链,最后统计求和即可

      1 /*
      2     Problem:
      3     OJ:
      4     User:    S.B.S.
      5     Time:
      6     Memory:
      7     Length:
      8 */
      9 #include<iostream>
     10 #include<cstdio>
     11 #include<cstring>
     12 #include<cmath>
     13 #include<algorithm>
     14 #include<queue>
     15 #include<cstdlib>
     16 #include<iomanip>
     17 #include<cassert>
     18 #include<climits>
     19 #include<functional>
     20 #include<bitset>
     21 #include<vector>
     22 #include<list>
     23 #include<map>
     24 #define F(i,j,k) for(int i=j;i<=k;i++)
     25 #define M(a,b) memset(a,b,sizeof(a))
     26 #define FF(i,j,k) for(int i=j;i>=k;i--)
     27 #define BUG system("pause")
     28 #define maxn 200000
     29 #define inf 0x3f3f3f3f
     30 #define maxm 5000000
     31 //#define LOCAL
     32 using namespace std;
     33 int read(){
     34     int x=0,f=1;char ch=getchar();
     35     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     36     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
     37     return x*f;
     38 }
     39 int head[maxn],to[maxm],next[maxm];
     40 int dfn[maxn],low[maxn];
     41 int st[maxm],ed[maxm];
     42 int n,m,cnt,ans,anss,mod;
     43 int tot,belong[maxn],t,p,stk[maxn],val[maxn];
     44 bool instk[maxn];
     45 int num[maxn],in[maxn],dp[maxn],q[maxm],vis[maxn];
     46 inline void add(int u,int v)
     47 {
     48     to[cnt]=v; 
     49     next[cnt]=head[u]; 
     50     head[u]=cnt++;
     51 }
     52 inline void init()
     53 {
     54     memset(head,-1,sizeof(head));cnt=0;
     55     cin>>n>>m>>mod;
     56     for(int i=1;i<=m;i++)
     57     {
     58         cin>>st[i]>>ed[i];
     59         add(st[i],ed[i]);
     60     }
     61 }
     62 inline void dfs(int u)
     63 {
     64     low[u]=dfn[u]=++t;
     65     stk[++p]=u; instk[u]=true;
     66     for(int i=head[u];i!=-1;i=next[i])
     67     {
     68         if(!dfn[to[i]])
     69         {
     70             dfs(to[i]);
     71             low[u]=min(low[u],low[to[i]]);
     72         }
     73         else if(instk[to[i]]) low[u]=min(low[u],dfn[to[i]]);
     74     }
     75     if(dfn[u]==low[u])
     76     {
     77         tot++;
     78         int tmp=-1;
     79         while(tmp!=u)
     80         {
     81             tmp=stk[p--];
     82             belong[tmp]=tot;
     83             val[tot]++;
     84             instk[tmp]=false;
     85         }
     86     }
     87 }
     88 inline void topsort()
     89 {
     90     int h=1,t=1,u;
     91     for(int i=1;i<=tot;i++)
     92         if(in[i]==0)
     93         {
     94             q[t++]=i;
     95             dp[i]=val[i];
     96             num[i]=1;
     97         }
     98     while(h<t)
     99     {
    100         u=q[h++];
    101         for(int i=head[u];i!=-1;i=next[i])
    102         {
    103             in[to[i]]--;
    104             if(in[to[i]]==0) q[t++]=to[i];
    105             if(vis[to[i]]==u) continue;
    106             if(dp[to[i]]<dp[u]+val[to[i]])
    107             {
    108                 dp[to[i]]=dp[u]+val[to[i]];
    109                 num[to[i]]=num[u];
    110             }
    111             else if(dp[to[i]]==dp[u]+val[to[i]])
    112             {
    113                 num[to[i]]=(num[to[i]]+num[u])%mod;
    114             }
    115             vis[to[i]]=u;
    116         }
    117     }
    118 }
    119 inline void go()
    120 {
    121     for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i);
    122     memset(head,-1,sizeof(head));cnt=0;
    123     for(int i=1;i<=m;i++)
    124         if(belong[st[i]]!=belong[ed[i]])
    125         {
    126             add(belong[st[i]],belong[ed[i]]);
    127             in[belong[ed[i]]]++;
    128         }
    129     topsort();
    130     for(int i=1;i<=tot;i++)
    131     {
    132         if(dp[i]>ans)
    133         {
    134             ans=dp[i];
    135             anss=num[i];
    136         }
    137         else if(dp[i]==ans) anss=(anss+num[i])%mod;
    138     }
    139     cout<<ans<<endl<<anss<<endl;
    140 }
    141 int main()
    142 {
    143     std::ios::sync_with_stdio(false);//cout<<setiosflags(ios::fixed)<<setprecision(1)<<y;
    144     #ifdef LOCAL
    145     freopen("data.in","r",stdin);
    146     freopen("data.out","w",stdout);
    147     #endif
    148     init();
    149     go();
    150     return 0;
    151 }
    View Code
  • 相关阅读:
    CSP 模拟17
    晚测7
    CSP 模拟16
    CSP 模拟14
    CSP 模拟13
    Cypress系列(67)- 环境变量设置指南
    Cypress系列(66)- 测试运行最佳实践
    Cypress系列(65)- 测试运行失败自动重试
    Cypress系列(64)- 数据驱动策略
    Cypress系列(63)- 使用 Custom Commands
  • 原文地址:https://www.cnblogs.com/SBSOI/p/5916612.html
Copyright © 2011-2022 走看看