• 「BZOJ1093」[ZJOI2007] 最大半连通子图


    题意:

      给你一张图,要你新建一张子图。要求枚举原图中的所有边,如果某一条边链接的两个节点都在子图中,这条边一定要在子图中。如果新建的子图中的任意两点u, v满足u可以到v或v可以到u,则称这个子图为“半连通子图”。要你求出最大的半连通子图的节点数,以及最大的半连通子图的方案数有多少(方案数对C取模)

    题解:

      显然必须先缩点,同一个强连通分量里面的点一定满足半联通子图的定义。在缩点后建好的新图上面跑一个拓扑DP计算最长链和方案数。  

     1 #include<bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 const int maxn = 100005;
     6 const int maxm = 1000005;
     7 
     8 int n, m, MOD;
     9 int head[maxn], e[maxm << 1], toit[maxm << 1], nxt[maxm << 1];
    10 int dfn[maxn], low[maxn], q[maxn << 1], bel[maxn], hav[maxn];
    11 vector<int> G[maxn];
    12 bool inq[maxn];
    13 
    14 int tot = 1;
    15 void Add (int u,int v) {
    16     toit[++ tot] = v; nxt[tot] = head[u]; head[u] = tot;
    17 }
    18 
    19 int t = 0, scc = 0, top = 0;
    20 void Tarjan (int x) {
    21     dfn[x] = low[x] = ++ t; q[++ top] = x; inq[x] = 1;
    22     for (int i = head[x]; i; i = nxt[i]) {
    23         int v = toit[i];
    24         if (! dfn[v]) {
    25             Tarjan(v); low[x] = min(low[x], low[v]);
    26         } else if (inq[v]) low[x] = min(low[x], dfn[v]);
    27     }
    28     int now = 0;
    29     if (dfn[x] == low[x]) {
    30         ++ scc;
    31         while (now != x) {
    32             now = q[top --]; inq[now] = 0; hav[scc] ++; bel[now] = scc;
    33         }
    34     }
    35 }
    36 
    37 int ind[maxn];
    38 void Rebuild () {
    39     for (int x = 1; x <= n; ++ x) {
    40         for (int i = head[x]; i; i = nxt[i]) {
    41             int v = toit[i];
    42             if (bel[x] != bel[v]) {
    43                 G[bel[x]].push_back(bel[v]); 
    44                 ++ ind[bel[v]];
    45             }
    46         }
    47     }
    48 }
    49 
    50 int f[maxn], g[maxn], vis[maxn];
    51 void dp () {
    52     queue<int> Q; 
    53     for (int i = 1; i <= scc; ++ i) {
    54         if (! ind[i]) Q.push(i);
    55         f[i] = hav[i]; g[i] = 1;
    56     }
    57     while (! Q.empty()) {
    58         int x = Q.front(); Q.pop();
    59         for (unsigned i = 0; i < G[x].size(); ++ i) {
    60             int v = G[x][i]; -- ind[v];
    61             if (! ind[v]) Q.push(v);
    62             if (vis[v] == x) continue;
    63             if (f[x] + hav[v] > f[v]) {
    64                 f[v] = f[x] + hav[v];
    65                 g[v] = g[x];
    66             } else if (f[x] + hav[v] == f[v]) {
    67                 g[v] = (g[v] + g[x]) % MOD;                
    68             }
    69             vis[v] = x;
    70         }
    71     }
    72 }
    73 
    74 int main () {
    75     scanf("%d%d%d", &n, &m, &MOD);
    76     for (int i = 1; i <= m; ++ i) {
    77         int u, v; scanf("%d%d", &u, &v);
    78         Add(u, v);
    79     }
    80     for (int i = 1; i <= n; ++ i) if (! dfn[i]) Tarjan(i);
    81     Rebuild();
    82        dp();
    83        int Mx = 0, Ans = 0;
    84        for (int i = 1; i <= scc; ++ i) {
    85            if (f[i] > Mx) Mx = f[i], Ans = g[i];
    86            else if (f[i] == Mx) Ans = (Ans + g[i]) % MOD;
    87     }
    88     printf("%d
    %d
    ", Mx, Ans);
    89     return 0;
    90 }

     

  • 相关阅读:
    【第36题】2019年OCP认证12C题库062考试最新考试原题
    004 基本命令 touch cp mv 命令
    003 基本指令 mkdir rm -rf(暴力删除)
    002 文件目录类的指令 cd ls
    001 指定运行级别
    005 抽象工厂模式
    006 使用类加载器加载资源文件
    004 方法反射
    003 属性反射
    003 工厂方法模式
  • 原文地址:https://www.cnblogs.com/juruohx/p/9588461.html
Copyright © 2020-2023  润新知