• Codeforces Round #267 Div.2 D Fedor and Essay -- 强连通 DFS


    题意:给一篇文章,再给一些单词替换关系a b,表示单词a可被b替换,可多次替换,问最后把这篇文章替换后(或不替换)能达到的最小的'r'的个数是多少,如果'r'的个数相等,那么尽量是文章最短。

    解法:易知单词间有二元关系,我们将每个二元关系建有向边,然后得出一张图,图中可能有强连通分量(环等),所以找出所有的强连通分量缩点,那个点的minR,Len赋为强连通分量中最小的minR,Len,然后重新建图,跑一个dfs即可得出每个强连通分量的minR,Len,最后O(n)扫一遍替换单词,统计即可。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    #include <string>
    #include <vector>
    #include <stack>
    #include <map>
    #define INF 0x3f3f3f3f
    #define lll __int64
    using namespace std;
    #define N 100007
    
    struct Edge
    {
        int v,next;
    }G[4*N],G2[4*N];
    string ss[N];
    map<string,int> mp;
    int minR[4*N],Len[4*N];
    int nR[4*N],nLen[4*N];
    int head[4*N],tot,cnt,vis[4*N];
    int last[4*N],tot2;
    stack<int> stk;
    int instk[4*N],now,Time;
    int low[4*N],dfn[4*N],bel[4*N];
    lll sumR,sumLen;
    
    void addedge(int u,int v)
    {
        G[tot].v = v;
        G[tot].next = head[u];
        head[u] = tot++;
    }
    
    void addedge2(int u,int v)  //建新图
    {
        G2[tot2].v = v;
        G2[tot2].next = last[u];
        last[u] = tot2++;
    }
    
    void tarjan(int u)
    {
        low[u] = dfn[u] = ++Time;
        stk.push(u);
        instk[u] = 1;
        for(int i=head[u];i!=-1;i=G[i].next)
        {
            int v = G[i].v;
            if(!dfn[v])
            {
                tarjan(v);
                low[u] = min(low[u],low[v]);
            }
            else if(instk[v])
                low[u] = min(low[u],dfn[v]);
        }
        if(low[u] == dfn[u])
        {
            cnt++;
            int v;
            do{
                v = stk.top();
                stk.pop();
                instk[v] = 0;
                bel[v] = cnt;
                if(minR[v] < nR[cnt] || (minR[v] == nR[cnt] && Len[v] < nLen[cnt]))
                    nR[cnt] = minR[v],nLen[cnt] = Len[v];
            }while(u != v);
        }
    }
    
    void Tarjan()
    {
        memset(bel,0,sizeof(bel));
        memset(instk,0,sizeof(instk));
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        Time = 0,cnt = 0;
        while(!stk.empty()) stk.pop();
        int i;
        for(i=1;i<=now;i++)
            if(!dfn[i])
                tarjan(i);
    }
    
    void Build()
    {
        int i,j;
        memset(last,-1,sizeof(last));
        tot2 = 0;
        for(i=1;i<=now;i++)
        {
            for(j=head[i];j!=-1;j=G[j].next)
            {
                int v = G[j].v;
                if(bel[i] != bel[v])
                    addedge2(bel[i],bel[v]);
            }
        }
    }
    
    void dfs(int u)
    {
        if(vis[u]) return;
        vis[u] = 1;
        for(int i=last[u];i!=-1;i=G2[i].next)
        {
            int v = G2[i].v;
            dfs(v);
            if((nR[v] < nR[u]) || (nR[v] == nR[u] && nLen[v] < nLen[u]))
                nR[u] = nR[v],nLen[u] = nLen[v];
        }
    }
    
    int main()
    {
        int n,m,i,j,len;
        while(scanf("%d",&n)!=EOF)
        {
            now = 0;
            mp.clear();
            tot = 0;
            memset(head,-1,sizeof(head));
            memset(vis,0,sizeof(vis));
            for(i=1;i<=n;i++)
            {
                cin>>ss[i];
                len = ss[i].length();
                int cntR = 0;
                for(j=0;j<len;j++)
                {
                    if(ss[i][j] >= 'A' && ss[i][j] <= 'Z')
                        ss[i][j] = ss[i][j]-'A'+'a';
                    if(ss[i][j] == 'r')
                        cntR++;
                }
                if(!mp[ss[i]])
                    mp[ss[i]] = ++now;
                Len[mp[ss[i]]] = len;
                minR[mp[ss[i]]] = cntR;
            }
            scanf("%d",&m);
            string sa,sb;
            for(i=1;i<=m;i++)
            {
                sa = "", sb = "";
                cin>>sa>>sb;
                len = sa.length();
                int cntR = 0;
                for(j=0;j<len;j++)
                {
                    if(sa[j] >= 'A' && sa[j] <= 'Z')
                        sa[j] = sa[j]-'A'+'a';
                    if(sa[j] == 'r')
                        cntR++;
                }
                if(!mp[sa])
                    mp[sa] = ++now;
                int a = mp[sa];
                Len[a] = len;
                minR[a] = cntR;
    
                len = sb.length();
                cntR = 0;
                for(j=0;j<len;j++)
                {
                    if(sb[j] >= 'A' && sb[j] <= 'Z')
                        sb[j] = sb[j]-'A'+'a';
                    if(sb[j] == 'r')
                        cntR++;
                }
                if(!mp[sb])
                    mp[sb] = ++now;
                int b = mp[sb];
                Len[b] = len;
                minR[b] = cntR;
                addedge(a,b);
            }
            memset(nR,INF,sizeof(nR));     //新图的点的minR,Len
            memset(nLen,INF,sizeof(nLen));
            Tarjan();
            Build();
            for(i=1;i<=now;i++)
                if(!vis[i])
                    dfs(i);
            sumR = 0,sumLen = 0;
            for(i=1;i<=n;i++)
            {
                int u = bel[mp[ss[i]]];
                sumR += nR[u];
                sumLen += nLen[u];
            }
            printf("%I64d %I64d
    ",sumR,sumLen);
        }
        return 0;
    }
    View Code

    还有一种做法就是反向建图,然后sort一下,优先从最优的开始dfs,最后就能得出结果,但是我不知道这样为什么一定正确,如果你知道,那么请评论告诉我吧:)

  • 相关阅读:
    多线程
    序列化
    IO流
    递归
    JAVA异常处理
    java常用类-StringBuffer,Integer,Character
    系统测试过程
    备份,健壮,文档,在线帮助,网络,稳定性测试
    异常测试/恢复性测试(可靠)
    配置测试
  • 原文地址:https://www.cnblogs.com/whatbeg/p/3981194.html
Copyright © 2020-2023  润新知