UVA - 11324 The Largest Clique 强连通缩点+记忆化dp

来源:互联网 发布:杯子知乎 编辑:程序博客网 时间:2024/05/01 11:55

题目要求一个最大的弱联通图。

首先对于原图进行强连通缩点,得到新图,这个新图呈链状,类似树结构。

对新图进行记忆化dp,求一条权值最长的链,每个点的权值就是当前强连通分量点的个数。


/*Tarjan算法求有向图的强连通分量set记录了强连通分量Col记录了强连通分量的个数。*/#include <iostream>#include<cstring>#include<cstdio>#include<string>#include<algorithm>using namespace std;#define MAXN 2005#define MAXM 100005struct node{    int to,next;}edge[MAXM],edge2[MAXM];bool have[1005][1005];int sums[1005];int head[MAXN],head2[MAXN],en,en2;bool root[MAXN];int low[MAXN],dfn[MAXN],stack[MAXN],top,set[MAXN],col,num;bool vis[MAXN],instack[MAXN];int dp[MAXN];int n;int m;void addedge(int a,int b){    edge[en].to=b;    edge[en].next=head[a];    head[a]=en++;}void addedge2(int a,int b){    edge2[en2].to=b;    edge2[en2].next=head2[a];    head2[a]=en2++;}void tarjan(int u){    vis[u]=1;    dfn[u]=low[u]=++num;    instack[u]=true;    stack[++top]=u;    for(int i=head[u];i!=-1;i=edge[i].next)    {        int v=edge[i].to;        if(!vis[v])        {            tarjan(v);            low[u]=min(low[u],low[v]);        }        else            if(instack[v])                low[u]=min(dfn[v],low[u]);    }    if(dfn[u]==low[u])    {        int j;        col++;        do        {            j=stack[top--];            instack[j]=false;          set[j]=col;        }        while (j!=u);    }}void init(){    int i;    en=en2=top=col=num=0;    memset(head,-1,sizeof(head));    memset(head2,-1,sizeof(head2));    memset(instack,0,sizeof(instack));    memset(vis,0,sizeof(vis));    memset(set,-1,sizeof(set));    memset(have,0,sizeof(have));    memset(sums,0,sizeof(sums));    memset(root,true,sizeof(root));    memset(dp,-1,sizeof(dp));}int ans;int dfs(int now,int fa){    if(~dp[now]) return dp[now];    int maxs=sums[now];    for(int i=head2[now];~i;i=edge2[i].next)    {        int to=edge2[i].to;        if(to!=fa)        {            maxs=max(maxs,sums[now]+dfs(to,now));        }    }    return dp[now]=maxs;}int main(){    int a,b;    int cas;    scanf("%d",&cas);    while(cas--)    {        scanf("%d%d",&n,&m);        init();        for(int i=1;i<=m;i++)        {            scanf("%d%d",&a,&b);            addedge(a,b);        }        for(int i=1;i<=n;i++)            if(!vis[i])tarjan(i);        for(int i=1;i<=n;i++)        {            sums[set[i]]++;            for(int j=head[i];~j;j=edge[j].next)            {                int to=edge[j].to;                if(set[i]!=set[to]&&!have[set[i]][set[to]])                {                    addedge2(set[i],set[to]);                    root[set[to]]=false;                    have[set[i]][set[to]]=have[set[to]][set[i]]=true;                }            }        }        ans=0;        for(int i=1;i<=col;i++)        {            if(root[i])            {                dfs(i,-1);                ans=max(ans,dp[i]);            }        }        printf("%d\n",ans);    }    return 0;}


5 0
原创粉丝点击