题目链接:https://vjudge.net/contest/219056#problem/A

推荐博客:https://blog.csdn.net/ck_boss/article/details/39429285

发现上面的这位大佬的思路和我一样,自己代码太多错误就参考了一下。

题意:

输入n,接下来会输入输入n个字符串,然后输入m,接下来会输入m对字符串,每一对表示左边的字符串可以变成右边的字符串,但是右边的不可以变成左边的。字符串不论大小写,现在要我们经过变换把一开始的n个字符里面的字符  ' r'或'R'(不分大小写,你全部改成大写或小写)最少,如果有多个r最少,那么就换成总长度最短的,输出r的个数和总长度。

额,网上大多数好像使用BFS写的,但是我写得时候因为在做图论的题,就强行联想到了tarjan算法,然后就不想换思路,就用tarjan加DFS写了,代码比较长而且比较难看,先说一下思路,有兴趣的可以看代码,虽然比较。。。

思路就是先tarjan缩点,把可以两两相互替换的字符串(在同一个强连通分量里面)缩点染色,同时记录这个强连通分量里面最小的r个数和对于最短的长度。之后把缩完的点二次建图,最后用DFS找答案。

代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<vector>
#include<set>
#include<cstdio>
#include<string>
#include<deque>
using namespace std;
typedef long long LL;
#define eps 1e-8
#define INF 0x3f3f3f3f
#define maxn 100005
struct node{int value,length;
}dot[maxn],min1[maxn];//dot数字记录每个字符串编号之后对应的值
//min1数组记录染色之后每个强连通分量里面最符合的值
struct EDGE{int v,next;
}edge[maxn],edge2[maxn];//这里要两次建图,一次是给字符串编号之后建图,还有一次是缩点之后重新建图
int a[maxn];
int head[maxn],head2[maxn];
int dfn[maxn],low[maxn],color[maxn],s[maxn];
int n,m,k,t;
int cnt,time,ans,id,top,num,cnt2;
map<string,int>mp;//给每个字符串编号
map<pair<int,int>,int>mmp;//重新建图的时候防止重复的边
bool vis[maxn];
void init()
{mmp.clear();mp.clear();memset(head,-1,sizeof(head));memset(dfn,0,sizeof(dfn));memset(head2,-1,sizeof(head2));cnt=time=ans=id=top=num=0;memset(vis,false,sizeof(vis));cnt2=0;for(int i=0;i<maxn;i++){min1[i].length=min1[i].value=INF;}
}
void cal(string &s)//编号并计算r的个数和字符串长度
{mp[s]=++id;int value=0;for(int i=0;i<s.size();i++){if(s[i]=='r')value++;}dot[mp[s]].value=value;//dot记录字符串s对应编号的r个数和长度 dot[mp[s]].length=s.size();
}
void tarjan(int u)//缩点染色
{dfn[u]=low[u]=++time;s[top++]=u;vis[u]=true;for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].v;if(!dfn[v]){tarjan(v);low[u]=min(low[u],dfn[v]);}else if(vis[v])//必须要在栈内,因为这里不一定是一个连通图,所以一定要判断是否在栈内//并且一定要写成dfn[v],不能写成low[u] low[u]=min(low[u],dfn[v]);}if(low[u]==dfn[u]){ans++;int v;do{v=s[--top];vis[v]=false;color[v]=ans;if(dot[v].value<min1[ans].value||dot[v].value==min1[ans].value&&dot[v].length<min1[ans].length){//min1数组记录每个强连通分量里面最优的结果 min1[ans].value=dot[v].value;min1[ans].length=dot[v].length;}}while(v!=u);}
}
void addedge(int u,int v)
{edge[++cnt].v=v;edge[cnt].next=head[u];head[u]=cnt;
}
void addedge2(int u,int v)
{edge2[++cnt2].v=v;edge2[cnt2].next=head2[u];head2[u]=cnt2;
}
void get_edge2()
{for(int i=1;i<=id;i++){for(int j=head[i];j!=-1;j=edge[j].next){int v=edge[j].v;if(color[i]!=color[v]&&mmp[make_pair(color[i],color[v])]==0){addedge2(color[i],color[v]);mmp[make_pair(color[i],color[v])]=1;}//两个强连通分量之间建一条有向图,可能有重复边,我们用mmp记录去掉
        }}
}
node bijiao(node s1,node s2)
{if(s1.value<s2.value||s1.value==s2.value&&s1.length<s2.length)return s1;return s2;
}
void DFS(LL u)
{if(vis[u])return;vis[u]=true;for(int i=head2[u];i!=-1;i=edge2[i].next){int v=edge2[i].v;if(!vis[v])DFS(v);min1[u]=bijiao(min1[u],min1[v]);}return;
}
string ope(string str)
{for(int j=0;j<str.size();j++){if(str[j]>='A'&&str[j]<='Z')//全部变成小写 str[j]=str[j]-'A'+'a';}return str;
}
int main()
{while(cin>>n){init();string str;for(int i=0;i<n;i++){cin>>str;str=ope(str);if(mp[str]==0)//编号
            cal(str);a[i]=mp[str];//记录文章里面字符串的编号
        }cin>>m;string s1,s2;for(int i=0;i<m;i++){cin>>s1>>s2;s1=ope(s1);s2=ope(s2);if(mp[s1]==0)cal(s1);if(mp[s2]==0)cal(s2);addedge(mp[s1],mp[s2]);//建图,从s1的编号到s2的编号的有向边
        }for(int i=1;i<=id;i++)//求强连通分量
        {if(!dfn[i])tarjan(i);}get_edge2();//缩点之后重新建图 LL sum1=0,sum2=0;int flag[maxn];memset(vis,false,sizeof(vis));memset(flag,0,sizeof(flag));//DFS(c);//试了无数次,不知道这句为什么放在这里就错了 ,不然可以节省很多时间 for(int i=0;i<n;i++){LL c=color[a[i]];if(!flag[c]){memset(vis,0,sizeof(vis));
                DFS(c);//不知道为啥放在这里就对了 flag[c]=1;}sum1+=min1[c].value;sum2+=min1[c].length;}cout<<sum1<<' '<<sum2<<endl;}return 0;
}

转载于:https://www.cnblogs.com/6262369sss/p/9799224.html

缩点+染色+DFS codeforce467D相关推荐

  1. POJ - 3160 Father Christmas flymouse tanjar缩点构图+dfs

    传送门 题意:给你一个图,每一个点可以获得一个愉悦值,求能从某一个点出发走能得到的最大愉悦值.路径为单项的,显然不会加上负的.可以通过tanjar缩点从而形成DAG,再跑一个计划搜索即可求出. 怎么缩 ...

  2. hdu6165 缩点,dfs

    hdu6165    FFF at Valentine 题意:给出一个有向图,问任意两个点 a.b,是否可以从a到b,或者从b到a. tags:主要是题意有点绕.. 只要 tarjan 缩点成 DAG ...

  3. P1506 拯救oibh总部(染色+dfs)

    思路:挺好的一个染色问题,从图的周围开始染色. 代码如下: #include<bits/stdc++.h> #define ll long long using namespace std ...

  4. bzoj1304 [CQOI2009]叶子的染色 dfs+树形dp

    这个类型的题应该是做过很多次,但做起来还是比较慢 这个题常规方法是枚举根,但这样是n^2的,这样就考虑优化 可以作为根的点一定构成一棵树,所以每次找相邻的点一定可以考虑所有情况 然后就是如何用父节点的 ...

  5. 强联通分量算法的个人详解Tarjan算法(包含缩点)

    有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected) ...

  6. [USACO5.3]校园网Network of Schools 缩点

    题目描述 一些学校连入一个电脑网络.那些学校已订立了协议:每个学校都会给其它的一些学校分发软件(称作"接受学校").注意即使 B 在 A 学校的分发列表中, A 也不一定在 B 学 ...

  7. POJ 3177 Redundant Paths (边双连通+缩点)

    <题目链接> <转载于 >>>  > 题目大意: 有n个牧场,Bessie 要从一个牧场到另一个牧场,要求至少要有2条独立的路可以走.现已有m条路,求至少要新 ...

  8. 染色法判断无向图是否为二部图

    二分图 二分图又称作二部图,是图论中的一种特殊模型. 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的 ...

  9. 洛谷p1506——拯救oibh总部 Java题解 DFS

    看了一下java的题解比较少,来发表一下Java AC代码.用的是DFS,染色题型. import java.util.*; public class Main{static Scanner sc=n ...

最新文章

  1. vue 项目配置sass
  2. CSS盒子模型(border、padding、margin、圆角边框、盒子阴影、文字阴影、新闻列表综合案例、新浪导航栏案例)
  3. 第三章 C#程序结构 (3.3 循环结构)
  4. Struts2笔记——初次框架配置
  5. 连接moogDB数据库
  6. oracle9i的erp数据库无法正常关闭的解决方法。
  7. android ble 调试工具,分享一个蓝牙BLE调试小程序LightBlue
  8. myBatis association的两种形式
  9. 【渝粤教育】电大中专营销策划原理与实务作业 题库
  10. MySQL 性能优化一
  11. 思科SDN技术:ACI架构概述
  12. 打印时显示rpc服务器不可用,打印时出现RPC服务器不可用 ?
  13. python dispatch函数_从Python调用CAPL函数
  14. java开源项目地址
  15. Motion Planning中的问题与挑战
  16. 层次分析法——确定指标权重、解决评价类问题
  17. 百度又一神器发布!网友:牛逼炸了...
  18. opencv3学习:reshape函数
  19. 梅姨眼中最爱读英国书籍的人竟然是TA?
  20. CSS盒模型(详解)

热门文章

  1. 岛屿类-网格类问题-DFS | 力扣200. 岛屿数量
  2. 模拟网络通信中存储转发的分组交换算法
  3. mybatis中传入String类型参数的问题
  4. 动词ing基本用法_动词ing形式的用法及变化规则
  5. L2-003 月饼-团体程序设计天梯赛GPLT
  6. dim private public static_C++ 强制类型转换操作符 static_cast
  7. 综合评价模型的缺点_视频/图像质量评价综述(一)
  8. 2021年下半年软考报考流程!
  9. 阿里云引领云原生进化,智能、互联、可信三位一体
  10. 关于容器迁移、运维、查错与监控,你想知道的都在这里了