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[*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的更多相关文章
- 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 ...
- 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 ...
- 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 ...
- 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 ...
- 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 ...
- 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 ...
- Codeforces Round #390 (Div. 2) D. Fedor and coupons(区间最大交集+优先队列)
http://codeforces.com/contest/754/problem/D 题意: 给定几组区间,找k组区间,使得它们的公共交集最大. 思路: 在k组区间中,它们的公共交集=k组区间中右端 ...
- Codeforces Round #267 (Div. 2)
A #include <iostream> #include<cstdio> #include<cstring> #include<algorithm> ...
- Codeforces Round #267 (Div. 2) C. George and Job DP
C. George and Job The new ITone 6 has been released ...
随机推荐
- [moka同学笔记]yii2.0小物件的简单使用(第一种方法)
这是第一种方法,还有另一种方法,其实都差不多. 1.在创建widgets\HelloWiget.php <?php /** * Created by PhpStorm. * User: Admi ...
- SQL数据库基础(六)
子查询,又叫做嵌套查询. 将一个查询语句做为一个结果集供其他SQL语句使用,就像使用普通的表一样,被当作结果集的查询语句被称为子查询. 子查询有两种类型: 一种是只返回一个单值的子查询,这时它可以用在 ...
- [ASP.NET MVC] 使用CLK.AspNet.Identity提供以角色为基础的访问控制(RBAC)
[ASP.NET MVC] 使用CLK.AspNet.Identity提供以角色为基础的访问控制(RBAC) 程序代码下载 程序代码下载:点此下载 前言 ASP.NET Identity是微软所贡献的 ...
- 2013 最新的 play web framework 版本 1.2.3 框架学习文档整理
Play framework框架学习文档 Play framework框架学习文档 1 一.什么是Playframework 3 二.playframework框架的优点 4 三.Play Frame ...
- 【使用 DOM】使用 DOM 元素
1. 使用元素对象 HTMLElement对象提供了一组属性,可以用它们来读取和修改被代表的数据.下表介绍了这些属性. 下面代码展示了如何使用表中所列的一些基本属性. <!DOCTYPE htm ...
- JS-取出字符串中重复次数最多的字符并输出
/** 取出字符串中重复字数最多的字符 */ var words = 'sdfghjkfastgbyhnvdstyaujskgfdfhlaa'; //创建字符串 var word, //单个字符 le ...
- SET UPDATE TASK LOCAL
SET Effect Switches on the local update task. This means that when you specify CALL FUNCTION ... IN ...
- 终端环境之tmux
今天继续介绍我的终端环境,tmux. why tmux? 用一个工具的第一问自然还是为什么要用.其实当时使用tmux的原因很简单.工作中经常需要长时间的编译.总想要下班后要关机的情况下,(肯定有人问我 ...
- Android-adb 常用命令 和 sqlite
Android开发环境中,ADB是我们进行Android开发经常要用的调试工具,它的使用当然是我们Android开发者必须要掌握的. ADB概述 Android Debug Bridge,Androi ...
- UITableView小知识点总结
1.UITableView去除空的cell,多余不用的 在viewdidload方法里加上这一句即可 self.tableView.tableFooterView = [[UIView alloc] ...