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 ...
随机推荐
- Python基础(一),Day1
python的安装 python2.x与3.x的部分区别 第一个python程序 变量 字符编码 注释 格式化字符串 用户输入 常用的模块初始 if判断 循环语句 作业 1.python的安装 可以在 ...
- PHP学习笔记:APACHE配置虚拟目录、一个站点使用多域名配置方式
我用的是xmapp lite2016的集成包,配置虚拟目录教程如下: 找到httpd-vhosts.conf这个文件,这个文件一般是在xampp\apache\conf\extra这个路径下面,找不到 ...
- Dom4j 锁竞争性能低下解决
在最近的项目中使用 Dom4j 解析 xml 发现性能低下,有锁竞争的情况,解决如下: SAXParserFactory factory = new org.apache.xerces.jaxp.SA ...
- 学习总结——DOM
DOM(Document Object Model),即文档对象模型.DOM是针对HTML和XML文档的一个API,它描绘了一个层次化的节点树,允许开发人员添加.移除和修改页面的某一部分.在定义方面, ...
- 使用WebMatrix发布网站
使用WebMatrix发布网站 WebMatrix 简介: Microsoft WebMatrix 是微软最新的 Web 开发工具,它包含了构建网站所需要的一切元素.您可以从开源 Web 项目或者内置 ...
- R语言学习笔记:字符串处理
想在R语言中生成一个图形文件的文件名,前缀是fitbit,后面跟上月份,再加上".jpg",先不百度,试了试其它语言的类似语法,没一个可行的: C#中:"fitbit&q ...
- GCC编译器使用
一.GCC简介 通常所说的GCC是GUN Compiler Collection的简称,除了编译程序之外,它还含其他相关工具,所以它能把易于人类使用的高级语言编写的源代码构建成计算机能够直接执行的二进 ...
- 认识Runtime2
我定义了一个Person类作为测试. 其中Person.h: // // Person.h // Test // // Created by zhanggui on 15/8/16. // Copyr ...
- iOS设计模式之策略模式
策略模式(Strategy) 基本理解 面向对象的编程,并不是类越多越好,类的划分是为了封装,但分类的基础是抽象,具有相同属性和功能的对象的抽象集合才是类. 策略模式:它定义了算法家族,分别封装起来, ...
- iOS UI 之UILable
@interface ViewController : UIViewController @property (strong,nonatomic) UILabel *aLable; @property ...