CodeForces
题目链接:http://codeforces.com/problemset/problem/467/D
题意:一篇文章(不分大小写)有n个单词,有m个替换方式,后面的单词可以变成前面的单词,问文章在出现字母r最少的情况下,长度最短。
输出r的数量和长度。
思路:贪心的思路,将每个单词用最少的r单词替代,r数相同时就选长度最小。这里是用bfs来完成贪心。
处理:用map<string,int>mp把单词(字符串)编号,用编写的结构体s数值保存长度和r的数量。
用vector<int>v[]储存可以代替的单词编号。
用bfs搜索每一个单词下s符合条件的情况
代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<vector> #define inf 0x3f3f3f3f #include<queue> #include<map> using namespace std; typedef long long ll; const int maxn=1e5+10; struct node{ int len; int sumr; }s[2*maxn],p;//s存储编号后,该编号单词可表示最少r数下最短的。 int tot,n,m,flag[maxn]; map<string, int>mp; vector<int> v[maxn*2];//存编号后,该编号可以代替的单词编号 void cl(string& str)//单词处理,将单词编号,并记录其s数组下的值 { int len=str.length(); int cnt=0; for(int i=0;i<len;i++) { if('A'<=str[i]&&str[i]<='Z')//统一转化成小写字母 str[i]=str[i]-'A'+'a'; if(str[i]=='r')//记录'r'的数量 cnt++; } if(!mp.count(str))//找没出现的单词 { mp[str]=tot;//tot为编号 s[tot].len=len;//记录该编号的长度及r数量 s[tot++].sumr=cnt; } } void bfs()//广搜,将每个s代表的单词变成可以表示的最少r数是最短 { queue<int> q; for(int i=0;i<tot;i++) q.push(i); while(!q.empty()) { int t=q.front(); q.pop(); p=s[t]; int len=v[t].size(); for(int i=0;i<len;i++)//和每个可转换单词比较 { int x=v[t][i]; if(p.sumr<s[x].sumr)//r数量更少 { s[x].sumr=p.sumr; s[x].len=p.len; q.push(x); } else if(p.sumr==s[x].sumr&&s[x].len>p.len)//r数量相同,长度更短 { s[x].len=p.len; q.push(x); } } } } int main() { cin>>n; string str1,str2; for(int i=0;i<n;i++) { getchar(); cin>>str1; cl(str1); flag[i]=mp[str1];//记录每个单词的编号 } cin>>m; for(int i=0;i<m;i++) { cin>>str1>>str2; cl(str1); cl(str2); v[mp[str2]].push_back(mp[str1]);//可以取代,用编号表示 } bfs();//搜索后每个s的单词都是最小 ll sum=0,len=0; for(int i=0;i<n;i++)//求答案 { sum+=s[flag[i]].sumr; len+=s[flag[i]].len; } cout<<sum<<" "<<len<<endl; return 0; }