hdu3639 targin+缩点+建立反向图

题解:俺是菜鸟这题不会写,看题解的  点击打开链接

题目:一群人相互投票,票数可以传递,但是一个人只能从另一个人那里获得一张票,比如0->1  1->2 0->2

2获得的票数最多,有2张。求哪一些人获得的票数最多?

解题 :targin缩点后 得到一个DAG(有向无环图,顺便记录下每个强连通图包含的节点数),每个强连通图可以用一个唯一编号去代替,这样可以知道有多少个强连通图是没有出度的,我们的答案就在这些 没有出度的强连通图中。因为如果一个强连通图有出度,那么它一定不是得票最多的。

这样我们的问题就转化为: 求各个 没有出度的强连通图 能够让多少个 节点 汇聚到这里。为了方便我们统计,可以建立一个反图(节点和原图相同,但是边的方向全部相反),这时候原图出度为0的点,就变成了反图中 入度为0 的点,所以我们只需要对反图中所有 入度为 0 的强连通图 进行  bfs/dfs ,就可以得到有多少个 节点 可以汇聚到当前这个入度为0 的强连通图,最后比较取最大max,输出最大是max-1(去掉强连通图中的自己,自己不能投给自己)。至于最后输出强连通图中的节点就好办了,从小到大遍历每个节点0~n-1,判断它所在的连通图 可汇聚的节点数是不是max ,是的话就输出。


自己脑瓜不好使,想不建立反向图,直接用拓扑排序,但是wa了很久,算了,以后有时间再看看吧。

//targin+缩点+反向图    5000节点 30000边  限时2000ms 提交600ms
#include<stdio.h>
#include<queue>
#include<vector>
#include<set>
using namespace std;
int min(int a,int b)
{
    return a<b?a:b;
}
const int sz = 5000+10;
int cnt;
struct Edge
{
    int to;
    int next;
};
int n,m;
Edge edge[30000+10];
int head[sz];
int dfn[sz],low[sz],time;
int stack[sz];
bool instack[sz];
int ss;

int sc;
int belong[sz];
int ans[sz];
int in[sz];
//vector<int>node[sz];

vector<int>G[sz];//反向图的邻接表
int dp[sz];//每个强联通图得到的支持人数 
void addEdge(int from,int to)
{
    edge[++cnt].next = head[from];
    edge[cnt].to = to;
    head[from] = cnt;
}
void targin(int u)
{
    dfn[u] = low[u] = ++time;
    stack[ss++] = u;
    instack[u] = true;
    for(int i=head[u];i;i=edge[i].next)
    {
        if(dfn[edge[i].to]==0)targin(edge[i].to);
        if(instack[edge[i].to])low[u] = min(low[u],low[edge[i].to]);
    }
    if(low[u]==dfn[u])
    {
        sc ++;
        int v;
        int c = 0;
        do
        {
            v = stack[--ss];
            instack[v] = false;
            belong[v] = sc;
//            node[sc].push_back(v);
            c++;
        }while(v!=u);
        ans[sc] = c;
    }
}
int q[sz];
int qq;
int bfs(int u)
{
    bool visit[sz] = {0};
    int sum = 0;
    q[qq++] = u;
    visit[u] = 1;
    while(qq>0)
    {
        int top = q[--qq];
        sum = sum + ans[top];
        for(int i=0;i<G[top].size();i++)
        {
            if(!visit[G[top][i]])
            {
                visit[G[top][i]] = true;
                q[qq++]=G[top][i];
            }
        }
    }
    return sum;
}
void init()
{
    sc = cnt = ss = time = qq = 0;
    for(int i=0;i<=n;i++)
    {
        head[i] = 0;
        instack[i] = false;
        in[i] = 0;
        G[i].clear();
        dp[i] = 0;
        dfn[i] = low[i] = 0;
//        node[i].clear();
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    int ca = 0;
    while(ca<t)
    {
        ca ++;
        scanf("%d %d",&n,&m);
        init();
        for(int i=1;i<=m;i++)
        {
            int from,to;
            scanf("%d %d",&from,&to);
            addEdge(from,to);
        }
        for(int i=0;i<n;i++)
        {
            if(dfn[i]==0)
            {
                targin(i);
            }
        }
        for(int i=0;i<n;i++)
        {
            for(int j=head[i];j;j=edge[j].next)
            {
                if(belong[i]!=belong[edge[j].to])
                {
                    in[belong[i]] ++;
                    G[belong[edge[j].to]].push_back(belong[i]);//邻接 
                }
            }
        }
        int max = -1;
        for(int i=1;i<=sc;i++)
        {
            if(in[i]==0)
            {
                int sum = bfs(i);
                dp[i] = sum;
                if(sum>max)
                {
                    max = sum ;
                } 
            }
        }
        printf("Case %d: %d\n",ca,max-1);
        int flag = 0;
        for(int i=0;i<n;i++)
        {
            if(dp[belong[i]]==max)
            {
                if(flag==0)
                {
                    printf("%d",i);
                    flag = 1;
                }else{
                    printf(" %d",i);
                }
            }
        }
        printf("\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zark721/article/details/80331980