zoukankan      html  css  js  c++  java
  • hdu 1827 Summer Holiday // tarjan求缩点

    /*
    
    题目:
        听说lcy帮大家预定了新马泰7日游,Wiskey真是高兴的夜不能寐啊,他想着得快点
        把这消息告诉大家,虽然他手上有所有人的联系方式,但是一个一个联系过去实在
        太耗时间和电话费了。他知道其他人也有一些别人的联系方式,这样他可以通知其
        他人,再让其他人帮忙通知一下别人。你能帮Wiskey计算出至少要通知多少人,至
        少得花多少电话费就能让所有人都被通知到吗?
    
    分析:
        因为可以通过其他人来通知他们认识的人,所以这幅图可以用强连通分量变成一个
        缩点的图,所有相互强连通分支变成一个缩点,求的所有缩点中入度为0的缩点即为
        所求的需要通知的最小人数。然后再枚举所有人所在的缩点是否入度为0,是的话更
        新该缩点所需的最小费用即可
    
    
    */
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    
    using namespace std;
    
    const int V = 1005;
    const int INF = 1e9;
    
    vector<int> adj[V];
    
    int cost[V],n,m;
    int dfn[V],low[V],father[V],stack[V],bcnt,depth,top;
    bool instack[V];
    int id[V],cnt[V];
    
    void dfs(int u) //tarjan求缩点
    {
        instack[u] = true;
        low[u] = dfn[u] = ++depth;
        stack[++top] = u;
        int v;
        int len = adj[u].size();
        for(int i=0;i<len;i++)
        {
            v = adj[u][i];
            if(!low[v])
            {
                dfs(v);
                low[u] = min(low[u],low[v]);
            }
            else if(instack[v])
                low[u] = min(low[u],dfn[v]);
        }
        if(dfn[u]==low[u])
        {
            ++bcnt;
            do
            {
                v = stack[top--];
                instack[v] = false;
                father[v] = bcnt;
            }while(u!=v);
        }
    }
    
    void solve()
    {
        depth = top = bcnt = 0;
        memset(instack,false,sizeof(instack));
        memset(low,0,sizeof(low));
        for(int i=1;i<=n;i++)
            if(!low[i])
                dfs(i);
    
        memset(id,0,sizeof(id));
        int v,len;
        for(int i=1;i<=n;i++)   //统计所有缩点的入度
        {
            len = adj[i].size();
            for(int j=0;j<len;j++)
            {
                v = adj[i][j];
                if(father[i]!=father[v])
                    id[father[v]]++;
            }
        }
        int ci = 0;
        int ans = 0;
        for(int i=1;i<=bcnt;i++)    //缩点的数目即为bcnt
        {
            if(id[i]==0)    //统计入度为0的数目
                ci++;
            cnt[i] = INF;
        }
        for(int i=1;i<=n;i++)
        {
            v = father[i];
            if(id[v]==0)
                cnt[v] = min(cnt[v],cost[i]);   //更新费用
        }
        for(int i=1;i<=bcnt;i++)
            if(cnt[i]!=INF)
                ans += cnt[i];
        printf("%d %d\n",ci,ans);
    }
    
    int main()
    {
        freopen("sum.in","r",stdin);
        freopen("sum.out","w",stdout);
        int x,y;
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&cost[i]);
                adj[i].clear();
            }
            for(int i=1;i<=m;i++)
            {
                scanf("%d%d",&x,&y);
                adj[x].push_back(y);
            }
            solve();
        }
        return 0;
    }
  • 相关阅读:
    P1903 [国家集训队]数颜色 / 维护队列 莫对算法
    P1016 旅行家的预算 模拟 贪心
    P3948 数据结构 差分数组
    乘法逆元 模板
    二分法 最大化平均值
    HDU5213 Lucky 莫队算法 容斥定理
    P1083 借教室 差分数组
    发布订阅、redis的配置文件、redis的主从、redis的持久化、
    nosql、redis、性能测试、命令相关、redis的数据类型string、list、hash、set、zset、
    nginx的日志、禁止访问、反向代理、权重、nginx location匹配规则、location分离、WSGI、
  • 原文地址:https://www.cnblogs.com/yejinru/p/2520874.html
Copyright © 2011-2022 走看看