UVA11324.The Largest Clique最大团——scc+dp

来源:互联网 发布:中非混血儿受歧视知乎 编辑:程序博客网 时间:2024/04/27 15:10

http://www.bnuoj.com/v3/problem_show.php?pid=19742

题目描述:
给一张有向图G,求一个结点数最大的结点集,使得该结点集中任意两个结点u和v满足:要么u可以到达v,要么v可以到达u,或者可以相互到达

分析:
在最优方案中,同一个强连通分量中的点要么都选,要么都不选。把强连通分量收缩点后得到scc图,让每个scc结点的权等于它的结点数,则题目转化为求scc图上权最大的路径,由于scc图是一个DAG,可以用动态规划求解

#include<cstring>#include<cstdio>#include<vector>#include<algorithm>const int MAXN=1100;const int MAXM=50010;using namespace std;int dfs_clock,scc_cnt,sccno[MAXN],dfn[MAXN],low[MAXN],num[MAXN];int Stack[MAXN],top;bool instack[MAXN];struct Edge{    int to,next;}edge[MAXM];int head[MAXN],tot;void init(){    tot=scc_cnt=dfs_clock=0;    memset(head,0xff,sizeof(head));    memset(dfn,0,sizeof(dfn));    memset(num,0,sizeof(num));    memset(instack,false,sizeof(instack));}void addedge(int u,int v){    edge[tot].to=v;    edge[tot].next=head[u];    head[u]=tot++;}void Tarjan(int u){    int v;    low[u]=dfn[u]=++dfs_clock;    Stack[top++]=u;    instack[u]=1;    for(int i=head[u];i!=-1;i=edge[i].next){        v=edge[i].to;        if(!dfn[v]){            Tarjan(v);            low[u]=min(low[u],low[v]);        }        else if(instack[v]&&low[u]>dfn[v])            low[u]=dfn[v];    }    if(low[u]==dfn[u]){        scc_cnt++;        for(;;){            v=Stack[--top];            sccno[v]=scc_cnt;            instack[v]=0;            num[scc_cnt]++;            if(v==u) break;        }    }}vector<int> mp[MAXN];int dp[MAXN];int dfs(int u){    if(dp[u]) return dp[u];    dp[u]=num[u];    int v;    for(int i=0;i<mp[u].size();++i){        v=mp[u][i];        dp[u]=max(dp[u],dfs(v)+num[u]);    }    return dp[u];}void solve(int n){    int v;    for(int i=1;i<=n;++i){        if(!dfn[i])            Tarjan(i);    }    for(int i=1;i<=n;++i) mp[i].clear();    for(int u=1;u<=n;++u){        for(int i=head[u];i!=-1;i=edge[i].next){            v=edge[i].to;            if(sccno[u]!=sccno[v]){                mp[sccno[u]].push_back(sccno[v]);            }        }    }    int ans=0;    memset(dp,0,sizeof(dp));    for(int i=1;i<=scc_cnt;++i){        ans=max(ans,dfs(i));    }    printf("%d\n",ans);}int main(){    int T,u,v,n,m;    scanf("%d",&T);    while(T--){        scanf("%d%d",&n,&m);        init();        while(m--){            scanf("%d%d",&u,&v);            addedge(u,v);        }        solve(n);    }    return 0;}
0 0
原创粉丝点击