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


    传送门

    题目简单来说就是给一个有向图,将图转化为DAG图后,求图中最长链及最长链的个数。

    思路:

      ①用 tarjan 缩点重构将原图转换为一个有向无环图,让后在新图上跑 topo 即可求出最长链。

      ②最长链的个数可以用动态规划,设 e[ i ] 表示新图中以 i 为终点的方案数,那么 e[ i ] 就等于连到 i 且满足距离等于起点到 i 的临时最长距离的点的 e 之和。最后查找距离等于最长链的点,答案就是它们的方案数之和。

    标程:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<string>
    #include<cstdlib>
    #include<stack>
    #include<vector>
    #include<queue>
    #include<deque>
    #include<map>
    #include<set>
    using namespace std;
    #define maxn 1000001 
    int n,m,mod;
    int x[maxn],y[maxn];//存边 
    int cnt=0;
    int de[maxn],to[maxn],head[maxn],nex[maxn];//链式前向星 
    int ue[maxn];
    int t=0,w=0;
    int ans=0;
    int e[maxn];
    int dis[maxn];//topo
    int num=0,top=0,col=0;
    int dfn[maxn],low[maxn],st[maxn],co[maxn],ins[maxn];//tarjan
    int nu[maxn];//重新记录边(去重) 
    inline  int read()
    {
        int kr=1,xs=0;
        char ls;
        ls=getchar();
        while(!isdigit(ls))
        {
            if(!(ls^45))
                kr=-1;
            ls=getchar();
        }
        while(isdigit(ls))
        {
            xs=(xs<<1)+(xs<<3)+(ls^48);
            ls=getchar();
        } 
        return xs*kr;
    }
    inline void add(int x,int y)
    {
        nex[++cnt]=head[x];
        head[x]=cnt;
        to[cnt]=y;
    }
    inline void tarjan(int u)//tarjan缩点 
    {
        dfn[u]=low[u]=++num;
        st[++top]=u;
        for(int i=head[u];i;i=nex[i])
        {
            int v=to[i];
            if(!dfn[v])
            {
                tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else if(!co[v])
                low[u]=min(low[u],dfn[v]);
        }
        if(low[u]==dfn[u])
        {
            co[u]=++col;
            ++ins[col];//ins为强连通分量的大小 
            while(st[top]!=u)
            {
                ++ins[col];
                co[st[top]]=col;
                --top;
            }
            --top; 
        }
    }
    inline bool cmp(int a,int b)
    {
        if(x[a]!=x[b]) return x[a]<x[b];
        return y[a]<y[b];
    }
    inline void remove()//去除重边,否则会影响方案数的统计 
    {
        for(int i=1;i<=m;i++)
        {
            nu[i]=i;
            x[i]=co[x[i]];
            y[i]=co[y[i]];
        }
        sort(nu+1,nu+m+1,cmp);
    }
    
    inline void build_map()
    {
        remove(); //去除重边 
        cnt=0;
        memset(head,0,sizeof(head));
        for(int i=1;i<=m;i++)
        {
            int z=nu[i];
            if((x[z]!=y[z])&&(x[z]!=x[nu[i-1]]||y[z]!=y[nu[i-1]]))
            {
                ++de[y[z]];
                add(x[z],y[z]);
            }
        }
    }//重构图 
    inline void topo()
    {
        for(int i=1;i<=col;i++)
        {
            if(!de[i])
            {
                ue[++w]=i;
                dis[i]=ins[i];
                e[i]=1;
                if(dis[ans]<dis[i]) ans=i;
            } 
        }//topo排序初始入队 
        while(t<w)
        {
            int u=ue[++t];
            for(int i=head[u];i;i=nex[i])
            {
                int v=to[i];
                --de[v];
                if(dis[v]<dis[u]+ins[v])//临时最长距离被更新,重新统计方案数 
                {
                    dis[v]=dis[u]+ins[v];
                    e[v]=0;
                    if(dis[ans]<dis[v]) ans=v;
                } 
                if(dis[v]==dis[u]+ins[v])//满足距离条件,累加方案数 
                {
                    e[v]=(e[v]+e[u])%mod;
                }
                if(!de[v]) ue[++w]=v;
            }
        }//topo排序 
    }
    int main()
    {
        n=read();m=read();mod=read();
        for(int i=1;i<=m;i++)
        {
            x[i]=read();y[i]=read();
            add(x[i],y[i]);
        }
        for(int i=1;i<=n;i++)
            if(!dfn[i])
                tarjan(i);
        build_map();//重构图 
        topo();//topo寻找最长链和最长链个数 
        int tot=0;
        for(int i=1;i<=n;i++)
            if(dis[i]==dis[ans])//统计答案 
                tot=(tot+e[i])%mod; 
        printf("%d
    %d
    ",dis[ans],tot);//输出最长距离、方案数 
    return 0;
    }
  • 相关阅读:
    分页系统
    ORM-数据处理
    Django的用法
    登录cookie写法
    MySQL数据库的安装创建
    前端弹框编写
    ADB常用指令
    Appium环境配置
    Jmeter中传递cookie值
    Jmeter从文件中读取参数值
  • 原文地址:https://www.cnblogs.com/lck-lck/p/9709367.html
Copyright © 2020-2023  润新知