zoukankan      html  css  js  c++  java
  • 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,最后就能得出结果,但是我不知道这样为什么一定正确,如果你知道,那么请评论告诉我吧:)

  • 相关阅读:
    网络安全分析
    java实现 洛谷 P1464 Function
    java实现 洛谷 P1464 Function
    java实现 洛谷 P1014 Cantor表
    java实现 洛谷 P1014 Cantor表
    java实现 洛谷 P1014 Cantor表
    java实现 洛谷 P1014 Cantor表
    java实现 洛谷 P1014 Cantor表
    java实现 洛谷 P1540 机器
    java实现 洛谷 P1540 机器
  • 原文地址:https://www.cnblogs.com/whatbeg/p/3981194.html
Copyright © 2011-2022 走看看