zoukankan      html  css  js  c++  java
  • Luogu P2272 / loj10092 / ZJOI2007最大半连通子图

    题目地址

    通过观察可得:

    1.一个强连通分量为一个半连通子图


    2.一条链为一个半连通子图

    执行$tarjan$算法缩点后,得到的图是一个DAG,使每个点的权值为这个点所包含的点数,问题就转化成了求DAG上的最长链(链上的点权值和最大)的大小和个数。

    既然是DAG,很明显可以想到DP。

    $f[u]$为以点$u$结尾的链的最大长度,那么很明显,状态转移方程为$f[v] = max(f[v],f[u] + size[v])$。

    $g[u]$为以点$u$结尾的最大链的个数,当$f[v] < f[u] + size[v]$时,$g[u] = f[u]$,当$f[v] = f[u] + size[v]$时,$g[u] = g[u] + 1$

    这样去DP的话,是需要拓扑排序的,如果$tarjan$缩点后去处理每个点的入度明显会超时。

    这里有一个技巧,$tarjan$是DFS,深度优先遍历整个图,只要从强连通分量的数量倒着枚举到一,就是缩点后形成的DAG的拓扑序。

    另外注意DP时注意重边,要去重。

    $Code:$

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <vector>
    #include <stack>
    #include <cstring>
    
    using namespace std;
    
    const int MAXN = 100000 + 10;
    
    int n,m,k,x;
    int low[MAXN],dfn[MAXN],color[MAXN],nodecnt,cnt,f[MAXN],siz[MAXN],ans,num[MAXN];
    int vis[MAXN];
    vector<int> e[MAXN];
    vector<int> en[MAXN];
    stack<int> s;
    
    void tarjan(int u) {
        dfn[u] = low[u] = ++cnt;
        s.push(u);
        int len = e[u].size();
        for(int i = 0; i < len; i++) {
            int v = e[u][i];
            if(!dfn[v]) {
                tarjan(v);
                low[u] = min(low[u],low[v]);
            }
            else if(!color[v]){
                low[u] = min(low[u],dfn[v]);
            }
        }
        if(low[u] == dfn[u]) {
            ++nodecnt;
            int t;
            do{
                siz[nodecnt]++;
                t = s.top();
                s.pop();
                color[t] = nodecnt;
            }while(t != u);
        }
    }
    
    void DP() {
        for(int i = nodecnt; i >= 1; i--) {
            int len = en[i].size();
            for(int j = 0; j < len; j++) {
                int v = en[i][j];
                if(vis[v] == i) continue;
                vis[v] = i;
                if(f[v] < f[i] + siz[v]) {
                    f[v] = f[i] + siz[v];
                    num[v] = num[i];
                }
                else if(f[v] == f[i] + siz[v]) {
                    num[v] += num[i];
                    num[v] %= x;
                }
            }
        }
    }
    
    int main() {
        scanf("%d%d%d",&n,&m,&x);
        for(int i = 1; i <= m; i++) {
            int u,v;
            scanf("%d%d",&u,&v);
            e[u].push_back(v);
        }
        for(int i = 1; i <= n; i++) {
            if(!dfn[i]) tarjan(i);
        }
        for(int i = 1; i <= n; i++) {
            int len = e[i].size();
            for(int j = 0; j < len; j++) {
                if(color[i] == color[e[i][j]]) continue;
                en[color[i]].push_back(color[e[i][j]]);
            }
        }
        for(int i = 1; i <= nodecnt; i++) {
            f[i] = siz[i];
            num[i] = 1;
        }
        DP();
        for(int i = 1; i <= nodecnt; i++) {
            if(f[i] > k) {
                k = f[i];
                ans = num[i];
                ans %= x;
            }
            else if(f[i] == k) {
                ans += num[i];
                ans %= x;
            }
        }
        printf("%d
    %d
    ",k,ans);
        return 0;
    }
  • 相关阅读:
    通用权限管理设计 之 数据库结构设计
    jQuery LigerUI 插件介绍及使用之ligerDateEditor
    jQuery LigerUI 插件介绍及使用之ligerTree
    jQuery LigerUI V1.01(包括API和全部源码) 发布
    jQuery liger ui ligerGrid 打造通用的分页排序查询表格(提供下载)
    jQuery LigerUI V1.1.5 (包括API和全部源码) 发布
    jQuery LigerUI 使用教程表格篇(1)
    jQuery LigerUI V1.0(包括API和全部源码) 发布
    jQuery LigerUI V1.1.0 (包括API和全部源码) 发布
    nginx keepalived
  • 原文地址:https://www.cnblogs.com/kjd123456/p/12616743.html
Copyright © 2011-2022 走看看