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

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

代码:

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <cstdlib>
  5. #include <cmath>
  6. #include <algorithm>
  7. #include <string>
  8. #include <vector>
  9. #include <stack>
  10. #include <map>
  11. #define INF 0x3f3f3f3f
  12. #define lll __int64
  13. using namespace std;
  14. #define N 100007
  15.  
  16. struct Edge
  17. {
  18. int v,next;
  19. }G[*N],G2[*N];
  20. string ss[N];
  21. map<string,int> mp;
  22. int minR[*N],Len[*N];
  23. int nR[*N],nLen[*N];
  24. int head[*N],tot,cnt,vis[*N];
  25. int last[*N],tot2;
  26. stack<int> stk;
  27. int instk[*N],now,Time;
  28. int low[*N],dfn[*N],bel[*N];
  29. lll sumR,sumLen;
  30.  
  31. void addedge(int u,int v)
  32. {
  33. G[tot].v = v;
  34. G[tot].next = head[u];
  35. head[u] = tot++;
  36. }
  37.  
  38. void addedge2(int u,int v) //建新图
  39. {
  40. G2[tot2].v = v;
  41. G2[tot2].next = last[u];
  42. last[u] = tot2++;
  43. }
  44.  
  45. void tarjan(int u)
  46. {
  47. low[u] = dfn[u] = ++Time;
  48. stk.push(u);
  49. instk[u] = ;
  50. for(int i=head[u];i!=-;i=G[i].next)
  51. {
  52. int v = G[i].v;
  53. if(!dfn[v])
  54. {
  55. tarjan(v);
  56. low[u] = min(low[u],low[v]);
  57. }
  58. else if(instk[v])
  59. low[u] = min(low[u],dfn[v]);
  60. }
  61. if(low[u] == dfn[u])
  62. {
  63. cnt++;
  64. int v;
  65. do{
  66. v = stk.top();
  67. stk.pop();
  68. instk[v] = ;
  69. bel[v] = cnt;
  70. if(minR[v] < nR[cnt] || (minR[v] == nR[cnt] && Len[v] < nLen[cnt]))
  71. nR[cnt] = minR[v],nLen[cnt] = Len[v];
  72. }while(u != v);
  73. }
  74. }
  75.  
  76. void Tarjan()
  77. {
  78. memset(bel,,sizeof(bel));
  79. memset(instk,,sizeof(instk));
  80. memset(dfn,,sizeof(dfn));
  81. memset(low,,sizeof(low));
  82. Time = ,cnt = ;
  83. while(!stk.empty()) stk.pop();
  84. int i;
  85. for(i=;i<=now;i++)
  86. if(!dfn[i])
  87. tarjan(i);
  88. }
  89.  
  90. void Build()
  91. {
  92. int i,j;
  93. memset(last,-,sizeof(last));
  94. tot2 = ;
  95. for(i=;i<=now;i++)
  96. {
  97. for(j=head[i];j!=-;j=G[j].next)
  98. {
  99. int v = G[j].v;
  100. if(bel[i] != bel[v])
  101. addedge2(bel[i],bel[v]);
  102. }
  103. }
  104. }
  105.  
  106. void dfs(int u)
  107. {
  108. if(vis[u]) return;
  109. vis[u] = ;
  110. for(int i=last[u];i!=-;i=G2[i].next)
  111. {
  112. int v = G2[i].v;
  113. dfs(v);
  114. if((nR[v] < nR[u]) || (nR[v] == nR[u] && nLen[v] < nLen[u]))
  115. nR[u] = nR[v],nLen[u] = nLen[v];
  116. }
  117. }
  118.  
  119. int main()
  120. {
  121. int n,m,i,j,len;
  122. while(scanf("%d",&n)!=EOF)
  123. {
  124. now = ;
  125. mp.clear();
  126. tot = ;
  127. memset(head,-,sizeof(head));
  128. memset(vis,,sizeof(vis));
  129. for(i=;i<=n;i++)
  130. {
  131. cin>>ss[i];
  132. len = ss[i].length();
  133. int cntR = ;
  134. for(j=;j<len;j++)
  135. {
  136. if(ss[i][j] >= 'A' && ss[i][j] <= 'Z')
  137. ss[i][j] = ss[i][j]-'A'+'a';
  138. if(ss[i][j] == 'r')
  139. cntR++;
  140. }
  141. if(!mp[ss[i]])
  142. mp[ss[i]] = ++now;
  143. Len[mp[ss[i]]] = len;
  144. minR[mp[ss[i]]] = cntR;
  145. }
  146. scanf("%d",&m);
  147. string sa,sb;
  148. for(i=;i<=m;i++)
  149. {
  150. sa = "", sb = "";
  151. cin>>sa>>sb;
  152. len = sa.length();
  153. int cntR = ;
  154. for(j=;j<len;j++)
  155. {
  156. if(sa[j] >= 'A' && sa[j] <= 'Z')
  157. sa[j] = sa[j]-'A'+'a';
  158. if(sa[j] == 'r')
  159. cntR++;
  160. }
  161. if(!mp[sa])
  162. mp[sa] = ++now;
  163. int a = mp[sa];
  164. Len[a] = len;
  165. minR[a] = cntR;
  166.  
  167. len = sb.length();
  168. cntR = ;
  169. for(j=;j<len;j++)
  170. {
  171. if(sb[j] >= 'A' && sb[j] <= 'Z')
  172. sb[j] = sb[j]-'A'+'a';
  173. if(sb[j] == 'r')
  174. cntR++;
  175. }
  176. if(!mp[sb])
  177. mp[sb] = ++now;
  178. int b = mp[sb];
  179. Len[b] = len;
  180. minR[b] = cntR;
  181. addedge(a,b);
  182. }
  183. memset(nR,INF,sizeof(nR)); //新图的点的minR,Len
  184. memset(nLen,INF,sizeof(nLen));
  185. Tarjan();
  186. Build();
  187. for(i=;i<=now;i++)
  188. if(!vis[i])
  189. dfs(i);
  190. sumR = ,sumLen = ;
  191. for(i=;i<=n;i++)
  192. {
  193. int u = bel[mp[ss[i]]];
  194. sumR += nR[u];
  195. sumLen += nLen[u];
  196. }
  197. printf("%I64d %I64d\n",sumR,sumLen);
  198. }
  199. return ;
  200. }

还有一种做法就是反向建图,然后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. [moka同学笔记]yii2.0小物件的简单使用(第一种方法)

    这是第一种方法,还有另一种方法,其实都差不多. 1.在创建widgets\HelloWiget.php <?php /** * Created by PhpStorm. * User: Admi ...

  2. SQL数据库基础(六)

    子查询,又叫做嵌套查询. 将一个查询语句做为一个结果集供其他SQL语句使用,就像使用普通的表一样,被当作结果集的查询语句被称为子查询. 子查询有两种类型: 一种是只返回一个单值的子查询,这时它可以用在 ...

  3. [ASP.NET MVC] 使用CLK.AspNet.Identity提供以角色为基础的访问控制(RBAC)

    [ASP.NET MVC] 使用CLK.AspNet.Identity提供以角色为基础的访问控制(RBAC) 程序代码下载 程序代码下载:点此下载 前言 ASP.NET Identity是微软所贡献的 ...

  4. 2013 最新的 play web framework 版本 1.2.3 框架学习文档整理

    Play framework框架学习文档 Play framework框架学习文档 1 一.什么是Playframework 3 二.playframework框架的优点 4 三.Play Frame ...

  5. 【使用 DOM】使用 DOM 元素

    1. 使用元素对象 HTMLElement对象提供了一组属性,可以用它们来读取和修改被代表的数据.下表介绍了这些属性. 下面代码展示了如何使用表中所列的一些基本属性. <!DOCTYPE htm ...

  6. JS-取出字符串中重复次数最多的字符并输出

    /** 取出字符串中重复字数最多的字符 */ var words = 'sdfghjkfastgbyhnvdstyaujskgfdfhlaa'; //创建字符串 var word, //单个字符 le ...

  7. SET UPDATE TASK LOCAL

    SET Effect Switches on the local update task. This means that when you specify CALL FUNCTION ... IN ...

  8. 终端环境之tmux

    今天继续介绍我的终端环境,tmux. why tmux? 用一个工具的第一问自然还是为什么要用.其实当时使用tmux的原因很简单.工作中经常需要长时间的编译.总想要下班后要关机的情况下,(肯定有人问我 ...

  9. Android-adb 常用命令 和 sqlite

    Android开发环境中,ADB是我们进行Android开发经常要用的调试工具,它的使用当然是我们Android开发者必须要掌握的. ADB概述 Android Debug Bridge,Androi ...

  10. UITableView小知识点总结

    1.UITableView去除空的cell,多余不用的 在viewdidload方法里加上这一句即可 self.tableView.tableFooterView = [[UIView alloc]  ...