图 - 强联通分量 - dp

题目大意:给你一张有向无权图,定义一个函数f(x)是O(g(x))的当且仅当存在常数C使得对于任意x都有f(x)<=C*g(x)。记f(L)表示这个图中长度为L的路径的数量,求最小的k使得f(L)是O(L^k)的。若不存在输出-1。
题解:不难发现图中无环则答案是0,有两个相交的环答案是-1。因此缩点,可以发现如果一条路经上有两组长度是2的环的话答案至少是1。因此猜测就是要找一条最长度路径,经过的环尽可能多。假设有k个环,那么答案就是max(0,k-1),dp即可。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<stack>
#include<queue>
#define gc getchar()
#define N 100010
#define M 1000010
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
struct edges{
    int to,pre;
}e[M];int h[N],etop,sta[N],nc[N],mc[N],bel[N],low[N],dfn[N],dfc,cc;stack<int> s;
inline int add_edge(int u,int v) { return e[++etop].to=v,e[etop].pre=h[u],h[u]=etop; }
int tarjan(int x)
{
    s.push(x),sta[x]=1,low[x]=dfn[x]=++dfc;
    for(int i=h[x],y;i;i=e[i].pre)
        if(sta[y=e[i].to]==1) low[x]=min(low[x],dfn[y]);
        else if(!sta[y]) low[x]=min(low[x],tarjan(y));
    if(low[x]==dfn[x])
    {
        for(cc++;s.top()!=x;s.pop())
            bel[s.top()]=cc;
        s.pop(),bel[x]=cc;
    }
    return sta[x]=2,low[x];
}
int d[N],us[M],vs[M],dp[N],ec,val[N];queue<int> q;
int main()
{
    int n=inn(),m=inn(),ans=0,hasc=0;
    for(int i=1,u,v;i<=m;i++) u=inn(),v=inn(),add_edge(u,v);
    for(int i=1;i<=n;i++) if(!sta[i]) tarjan(i);
    for(int x=1;x<=n;nc[bel[x]]++,x++)
        for(int i=h[x];i;i=e[i].pre)
            if(bel[x]==bel[e[i].to]) mc[bel[x]]++;
    for(int i=1;i<=cc;i++)
        if(nc[i]>1&&mc[i]>nc[i]) return !printf("-1\n");
        else if(nc[i]==mc[i]) val[i]=1,hasc=1;
    if(!hasc) return !printf("0\n");
    for(int x=1,y;x<=n;x++) for(int i=h[x],y;i;i=e[i].pre)
        if(bel[x]!=bel[y=e[i].to]) ec++,us[ec]=bel[x],vs[ec]=bel[y];
    memset(h,0,sizeof(int)*(n+1)),etop=0;
    for(int i=1;i<=ec;i++) add_edge(us[i],vs[i]),d[vs[i]]++;
    for(int i=1;i<=cc;i++) if(!d[i]) q.push(i);
    while(!q.empty())
    {
        int x=q.front();q.pop(),dp[x]+=val[x];
        for(int i=h[x];i;i=e[i].pre)
        {
            int y=e[i].to;d[y]--;
            dp[y]=max(dp[y],dp[x]);
            if(!d[y]) q.push(y);
        }
    }
    for(int i=1;i<=cc;i++) ans=max(ans,dp[i]);
    return !printf("%d\n",ans-1);
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/82351211