HDU 3639 Hawk-and-Chicken 强连通缩点+搜索

来源:互联网 发布:d3.js可视化 编辑:程序博客网 时间:2024/05/21 17:32

题目链接

http://acm.hdu.edu.cn/showproblem.php?pid=3594

题意

n个人,为了争夺谁是胜者,出给一个游戏规则,每个人都可以支持其他人,如A可以支持B为胜者,这种支持可以传递,如:A->B->C则支持C有两个人,如果成环,那么环中每个人都获得环中其他人所有人的支持。试求出获得支持数最多的人,如果有多个,按从小到大的顺序输出其编号。

思路

首先是强连通分量缩点,缩点的权值为缩点内原图中点的个数。因为是DAG图,所以反向建图,从入度为0的点出发累加路径上所有点的权值,累加得到的数值最大的点-1即是最大支持数(因为同一个缩点内需要减去自己)然后找出缩点累加值为最大的缩点,输出缩点中原图的点。 具体看代码

#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>#include<vector>#include<string>#include<queue>#include<stack>#include<set>#include<map>#define ll long longusing namespace std;const int INF = ( 2e9 ) + 2;const ll maxn = 5010;vector<int> g[2][maxn];int dfn[maxn],low[maxn],Stack[maxn],Belong[maxn],dp[maxn],w[maxn];int index,top,scc;bool Instack[maxn],vis[maxn],In[maxn];void tarjan(int u){    int v;    dfn[u]=low[u]=++index;    Stack[top++]=u;    Instack[u]=1;    for(int i=0,L=g[0][u].size(); i<L; i++)    {        v=g[0][u][i];        if(!dfn[v])        {            tarjan(v);            low[u]=min(low[u],low[v]);        }        else if(Instack[v])            low[u]=min(low[u],low[v]);    }    if(dfn[u]==low[u])    {        scc++;        do        {            v=Stack[--top];            Belong[v]=scc;            Instack[v]=0;            w[scc]++;           //缩点的权值为点中的个数         }        while(v!=u);    }}void getmap(int n){    memset(dfn,0,sizeof(dfn));    index=top=scc=0;    for(int i=0; i<n; i++)        if(!dfn[i])tarjan(i);    for(int i=0; i<n; i++)    {        for(int j=0,L=g[0][i].size(); j<L; j++)        {            int v=g[0][i][j];            if(Belong[i]!=Belong[v])            {                g[1][Belong[v]].push_back(Belong[i]); // 缩点图 :反向建的                 In[Belong[i]]=1;                        }        }    }}int dfs(int u){    int sum=w[u];    vis[u]=1;    for(int i=0,L=g[1][u].size(); i<L; i++)    {        int v=g[1][u][i];        if(vis[v])continue;        sum+=dfs(v);    }    return sum;}void init(int n){    for(int i=0; i<=n; i++)    {        g[0][i].clear();        g[1][i].clear();        dp[i]=-INF;    }    memset(w,0,sizeof(w));    memset(In,0,sizeof(In));}int main(){    int T;//  freopen("in.txt","r",stdin);    scanf("%d",&T);    for(int cas=1; cas<=T; cas++)    {        int n,m,u,v;        scanf("%d%d",&n,&m);        init(n);        for(int i=0; i<m; i++)        {            scanf("%d%d",&u,&v);            g[0][u].push_back(v);   //原图         }        getmap(n);        int mx=-1,f=1;        for(int i=1; i<=scc; i++)        if(In[i]==0)                // 从入度为0的点出发 ,累加所有可达点的权值         {            memset(vis,0,sizeof(vis));            int sum = dfs(i);            if(sum>mx)            {                mx=sum;            }            dp[i]=sum;        }        printf("Case %d: %d\n",cas,mx-1); // 答案最后为 mx-1 ,缩点内需要减去一个它本身         for(int i=0; i<n; i++)        {            if(dp[Belong[i]]==mx)            {                if(f)                {                    printf("%d",i);                    f=0;                }                else                    printf(" %d",i);            }        }        printf("\n");    }}
阅读全文
0 0
原创粉丝点击