题意:给一篇文章,再给一些单词替换关系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[*N],G2[*N];
string ss[N];
map<string,int> mp;
int minR[*N],Len[*N];
int nR[*N],nLen[*N];
int head[*N],tot,cnt,vis[*N];
int last[*N],tot2;
stack<int> stk;
int instk[*N],now,Time;
int low[*N],dfn[*N],bel[*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] = ;
for(int i=head[u];i!=-;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] = ;
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,,sizeof(bel));
memset(instk,,sizeof(instk));
memset(dfn,,sizeof(dfn));
memset(low,,sizeof(low));
Time = ,cnt = ;
while(!stk.empty()) stk.pop();
int i;
for(i=;i<=now;i++)
if(!dfn[i])
tarjan(i);
} void Build()
{
int i,j;
memset(last,-,sizeof(last));
tot2 = ;
for(i=;i<=now;i++)
{
for(j=head[i];j!=-;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] = ;
for(int i=last[u];i!=-;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 = ;
mp.clear();
tot = ;
memset(head,-,sizeof(head));
memset(vis,,sizeof(vis));
for(i=;i<=n;i++)
{
cin>>ss[i];
len = ss[i].length();
int cntR = ;
for(j=;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=;i<=m;i++)
{
sa = "", sb = "";
cin>>sa>>sb;
len = sa.length();
int cntR = ;
for(j=;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 = ;
for(j=;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=;i<=now;i++)
if(!vis[i])
dfs(i);
sumR = ,sumLen = ;
for(i=;i<=n;i++)
{
int u = bel[mp[ss[i]]];
sumR += nR[u];
sumLen += nLen[u];
}
printf("%I64d %I64d\n",sumR,sumLen);
}
return ;
}

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

Codeforces Round #267 Div.2 D Fedor and Essay -- 强连通 DFS的更多相关文章

  1. Codeforces Round #267 (Div. 2) D. Fedor and Essay tarjan缩点

    D. Fedor and Essay time limit per test 2 seconds memory limit per test 256 megabytes input standard ...

  2. Codeforces Round #267 (Div. 2) B. Fedor and New Game【位运算/给你m+1个数让你判断所给数的二进制形式与第m+1个数不相同的位数是不是小于等于k,是的话就累计起来】

    After you had helped George and Alex to move in the dorm, they went to help their friend Fedor play ...

  3. Codeforces Round #267 (Div. 2) B. Fedor and New Game

    After you had helped George and Alex to move in the dorm, they went to help their friend Fedor play ...

  4. 01背包 Codeforces Round #267 (Div. 2) C. George and Job

    题目传送门 /* 题意:选择k个m长的区间,使得总和最大 01背包:dp[i][j] 表示在i的位置选或不选[i-m+1, i]这个区间,当它是第j个区间. 01背包思想,状态转移方程:dp[i][j ...

  5. Codeforces Round #267 (Div. 2) C. George and Job(DP)补题

    Codeforces Round #267 (Div. 2) C. George and Job题目链接请点击~ The new ITone 6 has been released recently ...

  6. Codeforces Round #267 (Div. 2)D(DFS+单词hash+简单DP)

    D. Fedor and Essay time limit per test 2 seconds memory limit per test 256 megabytes input standard ...

  7. Codeforces Round #390 (Div. 2) D. Fedor and coupons(区间最大交集+优先队列)

    http://codeforces.com/contest/754/problem/D 题意: 给定几组区间,找k组区间,使得它们的公共交集最大. 思路: 在k组区间中,它们的公共交集=k组区间中右端 ...

  8. Codeforces Round #267 (Div. 2)

    A #include <iostream> #include<cstdio> #include<cstring> #include<algorithm> ...

  9. Codeforces Round #267 (Div. 2) C. George and Job DP

                                                  C. George and Job   The new ITone 6 has been released ...

随机推荐

  1. 【poj 2185】Milking Grid(字符串--KMP+问题分解)

    题意:给定一个由字符组成的矩阵,求出它的面积最小的覆盖矩阵.(感觉应该是可重叠的......* (・ω・)っ) 解法:KMP.行列互不影响,可以问题分解.先求出每一行的最小重复串,利用kmp中的nex ...

  2. 机器学习实战 - 读书笔记(05) - Logistic回归

    解释 Logistic回归用于寻找最优化算法. 最优化算法可以解决最XX问题,比如如何在最短时间内从A点到达B点?如何投入最少工作量却获得最大的效益?如何设计发动机使得油耗最少而功率最大? 我们可以看 ...

  3. TCMalloc优化MySQL、Nginx内存管理

    TCMalloc的全称为Thread-Caching Malloc,是谷歌开发的开源工具google-perftools中的一个成员. 与标准的glibc库的Malloc相比,TCMalloc库在内存 ...

  4. js填写银行卡号,每隔4位数字加一个空格

    1.原生js写法 !function () { document.getElementById('bankCard').onkeyup = function (event) { var v = thi ...

  5. [模仿][JS]新浪财经7*24直播

    使用新浪财经7*24直播的数据 简单的做一个山寨品 在线地址:[痛苦啊,有GFW,却没有vpn,往heroku上传浪费了好多时间...] http://wangxinsheng.herokuapp.c ...

  6. Virtual DOM 算法

    前端 virtual-dom react.js javascript 目录: 1 前言 2 对前端应用状态管理思考 3 Virtual DOM 算法 4 算法实现 4.1 步骤一:用JS对象模拟DOM ...

  7. Windows Python2.7环境 安装paramiko模块

    Paramiko是用python语言写的一个模块,遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接. 举个常见的例子,现有这样的需求:远程连接到Linux服务器,查看上面的日志状态,大家 ...

  8. 主程序底部TabBar功能跟登录页面布局

    1:主程序底部TabBar的功能实现 效果图: 主要代码如下: - (UITabBarController*)setRootVC:(BOOL)bShowCart { //创建一个子控制器 用于显示当前 ...

  9. Android环境的搭建

    一.Java环境的配置(以JDK1.7为例) 在环境变量下查看,查看是否存在JAVA_HOME,没有的话新建一个 JAVA_HOME:java安装目录下jdk的安装目录 Path:jdk目录下面的bi ...

  10. 转载:sql关联查询

    inner join(等值连接)只返回两个表中联结字段相等的行 left join(左联接)返回包括左表中的所有记录和右表中联结字段相等的记录 right join(右联接)返回包括右表中的所有记录和 ...