• P2272 [ZJOI2007]最大半连通子图


    Problem

    当一个有向图(G= (V,E))满足:(forall u,v in V,u o v)(v o u)
    求这个图的最大半联通子图(节点数最多)节点数和最大半联通子图个数模(X)的值。
    (n le 10^5,m le 10^6,X le 10^8)

    Solution

    显然SCC也是强连通子图。所以先用Tarjan缩点,然后将图变成一个DAG(套路)。问题转变成:求缩点完后的DAG中的最长链最长链个数。显然可以拓扑+dp。

    注意:缩点后会出现重边,要注意不能让重边加入,用个map记录即可。

    # include <bits/stdc++.h>
    using namespace std;
    # define int long long
    const int N = 1e5 + 5;
    int n,m,X;
    vector <int> g[N],g2[N];
    vector <pair<int,int> > G;
    int dfn[N],low[N],dfntot = 0,s[N],top = 0,scc_tot = 0,siz[N],belong[N],du[N];
    bool vis[N]; int dis[N],cnt[N];
    map<int,map<int,int> > check;
    void dfs(int x)
    {
        dfn[x] = low[x] = ++dfntot;
        s[++top] = x; vis[x] = 1;
        for(int i = 0; i < (int)g[x].size(); i++)
        {
            int v = g[x][i];
            if(!dfn[v]) 
            {
                dfs(v); low[x] = min(low[x],low[v]);
            }
            else if(vis[v]) low[x] = min(low[x],dfn[v]);
        }
        if(dfn[x] == low[x])
        {
            int temp = 0;
            ++scc_tot;
            do
            {   
                temp = s[top--];
                ++siz[scc_tot]; belong[temp] = scc_tot;
                vis[temp] = 0;
            }while(x != temp);
        }
        return;
    }
    void topsort(void)
    {
        queue <int> q;
        for(int i = 1; i <= scc_tot; i++)
        {
            if(du[i] == 0) {q.push(i); dis[i] = siz[i],cnt[i] = 1;}
        }
        while(!q.empty())
        {
            int x = q.front(); q.pop();
            for(int i = 0; i < (int)g2[x].size(); i++)
            {
                int v = g2[x][i];
                if(siz[v] + dis[x] > dis[v]) 
                {
                    dis[v] = dis[x] + siz[v];
                    cnt[v] = cnt[x];
                }
                else if(siz[v] + dis[x] == dis[v])
                {
                    cnt[v] = (cnt[v] + cnt[x]) % X;
                }
                if(--du[v] == 0) q.push(v);
            }
        }
        return;
    }
    signed main(void)
    {
        scanf("%lld%lld%lld",&n,&m,&X);
        for(int i = 1; i <= m; i++)
        {
            int a,b; scanf("%lld%lld",&a,&b);
            g[a].push_back(b);
            G.push_back(make_pair(a,b));
        }
        for(int i = 1; i <= n; i++)
        {
            if(!dfn[i]) dfs(i);
        }
        for(int i = 0; i < m; i++)
        {
            int u = belong[G[i].first],v = belong[G[i].second];
            if(u != v && !check[u][v]) g2[u].push_back(v),du[v]++,check[u][v] = 1;
        }
        topsort();
        int ans1 = 0,ans2 = 0;
        for(int i = 1; i <= scc_tot; i++)
        {
            if(ans1 < dis[i]) {ans1 = dis[i]; ans2 = cnt[i] % X;}
            else if(ans1 == dis[i]) {ans2 = (ans2 + cnt[i]) % X;}
        }
        printf("%lld
    %lld",ans1 % X,ans2);
        return 0;
    }
    
  • 相关阅读:
    git常用操作命令
    如何编写高质量代码
    Chrome调试工具简单介绍
    使用eclipse+tomcat搭建本地环境
    chrome设置--disable-web-security解决跨域
    利用Maven管理工程项目本地启动报错及解决方案
    用户输入验证【提升篇】
    简单【用户输入验证】
    【消息框】的返回值
    【消息框】的4种显示形式
  • 原文地址:https://www.cnblogs.com/luyiming123blog/p/15076310.html
Copyright © 2020-2023  润新知