题意:给一篇文章,再给一些单词替换关系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. [Redis] redis-cli 命令总结

    Redis提供了丰富的命令(command)对数据库和各种数据类型进行操作,这些command可以在Linux终端使用.在编程时,比如使用Redis 的Java语言包,这些命令都有对应的方法.下面将R ...

  2. 使用Jsoup解析html网页

    一.   JSOUP简介 在以往用java来处理解析HTML文档或者片段时,我们通常会采用htmlparser(http://htmlparser.sourceforge.net/)这个开源类库.现在 ...

  3. ArrayList等常见集合的排序问题

    对于ArrayList等常用的集合具体业务类,基本上都实现了Comparable接口,即可以用来比较装载的对象实体. 主要用Collections.sort方法对集合类中的对象进行排序 Collect ...

  4. SQL数据库基础(一)

    数据库: 结构化查询语言(Structured Query Language)简称SQL: 数据库管理系统(Database Management System)简称DBMS: 数据库管理员(Data ...

  5. XML的解析方式(Java)

    dom方式解析 根据XML的层级结构在内存中分配一个树形结构,把XML的标签.属性和文本都封装成对象 优点:如果很方便实现增删改操作 缺点:如果文件过大,会造成内存溢出   sax方式解析 采用事件驱 ...

  6. Python连接MySQL数据库

    连接MySQL数据库 源码: import MySQLdb #导入MySQLdb模块 print '连接数据库</br>' #连接MySQL数据库 connect the database ...

  7. NPOI Excel类

    using System;using System.Collections.Generic;using System.Linq;using System.Text;using NPOI.HSSF.Us ...

  8. Java解析XML三种常用方法

    1.使用DOM方式解析: package com.wzh.dom; import java.util.Iterator; import javax.xml.parsers.DocumentBuilde ...

  9. Setting up your App domain for SharePoint 2013

    from:http://sharepointchick.com/archive/2012/07/29/setting-up-your-app-domain-for-sharepoint-2013.as ...

  10. 安卓开发--android library projects cannot be launched错误

    最新因为学习,问技术友要了几个源代码,导入源代码的时候无法进行真机或者虚拟机测试. 原因:android library projects cannot be launched 百度了一下,解决方法很 ...