• UVA11324_The Largest Clique


    极大团。即求一个最大点集,使得点集中的任意两个点u,v至少存在u->v,或者v->u的路径。

    是这样做的,求出所有的联通分量,然后整个图就变成了无环图,把原来若干个点缩点,点权为分量的点数。这样相当于找一条权值最大的路径,因为无环了,所以这个可以通过先拓扑排序然后dp解决。

    这里重点说一下自己遇到的坑吧。

    d[cur]=low[cur]=++dfsclock;  绝不能是  d[cur]=low[cur]=d[fa]+1;

    后者是错的。

    我思考了好久后来才发现问题。如图:

    假设我们按照d[fa]+1的方法来打标记,那么当路径为1->2->3时候,递归返回的时候low[1]=1,low[2]=1,low[3]=2,而此时去访问4点,此时low[4]最少也只能是2,那么从程序的角度来说,也就认为了4是单独的强联通分量,这是不对的。

    但是如果我们按照++dfsclock的方法来打标记,那么low[1]=1,low[2]=1,low[3]=2,low[4]=2,但是此时d[4]=4,可以判断出不是一个单独的强连通分量。主要是通过++dfsclock可以判断是否以前被访问过,这里与源点距离无关,特别注意了。

    召唤代码君:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define maxn 1010
    #define maxm 202000
    using namespace std;
    
    int first[maxn],next[maxm],to[maxm],edge;
    int low[maxn],d[maxn],belong[maxn],scc;
    int U[maxm],V[maxm],stack[maxn],top;
    int f[maxn],sum[maxn],Q[maxn];
    int n,m,T,ans,dfsclock;
    
    bool cmp(int q1,int q2)
    {
        return d[q1]>d[q2];
    }
    
    void _init()
    {
        dfsclock=ans=top=scc=0,edge=-1;
        for (int i=1; i<=n; i++) first[i]=-1,low[i]=d[i]=belong[i]=0;
    }
    
    void addedge(int uu,int vv)
    {
        edge++;
        to[edge]=vv,next[edge]=first[uu],first[uu]=edge;
    }
    
    void dfs(int cur,int fa)
    {
    
        d[cur]=low[cur]=++dfsclock;
        stack[++top]=cur;
        for (int i=first[cur]; i!=-1; i=next[i])
        {
            if (belong[to[i]]) continue;
            if (!d[to[i]]) dfs(to[i],cur);
            low[cur]=min(low[cur],low[to[i]]);
        }
        if (low[cur]>=d[cur])
            for (scc++,f[scc]=0;;)
            {
                belong[stack[top--]]=scc;
                f[scc]++;
                if (stack[top+1]==cur) break;
            }
    }
    
    int get(int x)
    {
        if (d[x]!=0) return d[x];
        if (first[x]==-1) return d[x]=1;
    
        d[x]=0;
        for (int i=first[x]; i!=-1; i=next[i])
            d[x]=max(d[x],get(to[i])+1);
    
        return d[x];
    }
    
    int main()
    {
        scanf("%d",&T);
        while (T--)
        {
            scanf("%d%d",&n,&m);
            _init();
            for (int i=1; i<=m; i++)
            {
                scanf("%d%d",&U[i],&V[i]);
                addedge(U[i],V[i]);
            }
            for (int i=1; i<=n; i++)
                if (!d[i]) dfs(i,0);
            edge=-1;
            for (int i=1; i<=scc; i++) first[i]=-1,d[i]=0;
            for (int i=1; i<=m; i++)
                if (belong[U[i]]!=belong[V[i]])
                    addedge(belong[U[i]],belong[V[i]]);
    
            for (int i=1; i<=scc; i++)
            {
                Q[i]=i,sum[i]=0;
                if (!d[i]) d[i]=get(i);
            }
            sort(Q+1,Q+1+scc,cmp);
            for (int i=1; i<=scc; i++)
            {
                sum[Q[i]]+=f[Q[i]];
                ans=max(ans,sum[Q[i]]);
                for (int j=first[Q[i]]; j!=-1; j=next[j])
                    sum[to[j]]=max(sum[to[j]],sum[Q[i]]);
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    如有转载,请注明出处(http://www.cnblogs.com/lochan)
  • 相关阅读:
    case when then 根据不同条件 查询不同的数据 相当于 if-else if-else
    完美的拼接sql语句,中间可以加字符等东西,
    C++抽象类
    C #引用NuGet程序包MySQLData问题
    win10磁盘100%占用解决方法
    C# ASP.NetCore 检测到包降级
    VS 命令“npm install”已退出的问题
    序列化和反序列化含义
    数据库MySQL忘记本地密码
    MongoDB授予权限
  • 原文地址:https://www.cnblogs.com/lochan/p/3852465.html
Copyright © 2020-2023  润新知