这次的解题报告是有关tarjan算法的一道思维量比较大的题目(真的是原创文章,希望管理员不要再把文章移出首页)。

这道题蒟蒻以前做过,但是今天由于要复习tarjan算法,于是就看到codevs分类强联通分量里面只有这一道题。

题目是这样的:

“每个人都拥有一个梦,即使彼此不相同,能够与你分享,无论失败成功都会感动。爱因为在心中,平凡而不平庸,世界就像迷宫,却又让我们此刻相逢Our Home。”在爱的国度里有N个人,在他们的心中都有着一个爱的名单,上面记载着他所爱的人(不会出现自爱的情况)。爱是具有传递性的,即如果A爱B,B爱C,则A也爱C。
如果有这样一部分人,他们彼此都相爱,则他们就超越了一切的限制,用集体的爱化身成为一个爱心天使。
现在,我们想知道在这个爱的国度里会出现多少爱心天使。而且,如果某个爱心天使被其他所有人或爱心天使所爱则请输出这个爱心天使是由哪些人构成的,否则输出-1。

这是一个有向图上的问题,这道题很容易看出来一个爱心天使就是一群人互相爱然后组成的有向环。既然是有向的图求强联通分量,套上tarjan就行了。不过因为后面要输出爱心天使是由哪些人构成的,所以,我们需要记录每个人在哪个爱心天使里面,具体tarjan标程就是下面这样:

 1 void dfs(int u){
 2     low[u] = dfn[u] = ++dfs_clock;
 3     s.push(u);
 4     for(int i = 0;i < g[u].size();++i){
 5         int v = g[u][i];
 6         if(!dfn[v]){
 7             dfs(v);
 8             low[u] = min(low[u],low[v]);
 9         }
10         else if(!ind[v]){
11             low[u] = min(low[u],dfn[v]);
12         }
13     }
14     if(low[u] == dfn[u]){
15         scc_cnt++;
16         while(1){
17             int x = s.top();
18             s.pop();
19             ind[x] = scc_cnt;
20             sccno[scc_cnt]++;
21             if(x == u)break;
22         }
23     }
24 }
25 void find_scc(int n){
26     dfs_clock = scc_cnt = 0;
27     for(int i = 1;i <= n;++i){
28         if(!dfn[i])dfs(i);
29     }
30 }

如果有不懂的地方,就说明是tarjan算法还是没搞懂,请先搞定tarjan算法的基础再来看这道题。

然后就是求每个爱心天使被多少个人爱着(爱心天使也被属于它自己的人们爱着)。由于爱有传递性,我们很容易能想到传递闭包的问题。具体做法就是:

1.先求出来所有的爱心天使(在这里一个人也当作是一个爱心天使,但是输出爱心天使个数的时候,一个人组成的爱心天使是不算的)和这个爱心天使由多少个人组成。

2.给每个爱心天使编号(缩点),然后建立一个以“被爱”为方向的新的有向图。

3.在新的有向图中跑SPFA(为什么不用Floyd,这个时间复杂度太高了,所以我们还是选择scc_cnt遍的SPFA,时间复杂度最坏也就是O(nke),保证是超不了时间的。SPFA在这里起到的作用就是计算每个爱心天使的爱能否传递到某个天使)。

4.统计计数,如果size[某个爱心天使] == n的话,那么就按编号从小到大遍历每个人输出这个爱心天使由哪些人组成。如果没有任何一个爱心天使的size为n的话,(用一个数记录,如果b == 0)就输出-1.

然后呈现整体代码,还是不是很长,才刚139行。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <cmath>
  6 #include <stack>
  7 #include <vector>
  8 #include <set>
  9 #include <queue>
 10 using namespace std;
 11 const int maxn = 1005;
 12 int dfn[maxn],low[maxn],dfs_clock,n,ind[maxn],m,scc_cnt,a,b,size[maxn],sccno[maxn],tim = 0;
 13 struct edge{
 14     int u,v;
 15     edge(int a,int b):u(a),v(b){};
 16 };
 17 struct edges{
 18     int to,next,cost;
 19 }qmap[maxn<<3];
 20 vector<int>g[maxn];
 21 vector<int>gk[maxn];
 22 vector<edge>ga;
 23 int d[maxn],h[maxn];
 24 const int INF = 10000000;
 25 stack<int> s;
 26 void add(int u,int v){
 27     qmap[tim].to = v;qmap[tim].cost = 1;qmap[tim].next = h[u];h[u] = tim++;
 28 }
 29 void init(int n){
 30     memset(dfn,0,sizeof(dfn));
 31     memset(low,0,sizeof(low));
 32     memset(ind,0,sizeof(ind));
 33     memset(size,0,sizeof(size));
 34     memset(sccno,0,sizeof(sccno));
 35     memset(h,-1,sizeof(h));
 36     for(int i = 1;i <= n;++i){
 37         g[i].clear();
 38         gk[i].clear();
 39     }
 40 }
 41 void dfs(int u){
 42     low[u] = dfn[u] = ++dfs_clock;
 43     s.push(u);
 44     for(int i = 0;i < g[u].size();++i){
 45         int v = g[u][i];
 46         if(!dfn[v]){
 47             dfs(v);
 48             low[u] = min(low[u],low[v]);
 49         }
 50         else if(!ind[v]){
 51             low[u] = min(low[u],dfn[v]);
 52         }
 53     }
 54     if(low[u] == dfn[u]){
 55         scc_cnt++;
 56         while(1){
 57             int x = s.top();
 58             s.pop();
 59             ind[x] = scc_cnt;
 60             sccno[scc_cnt]++;
 61             if(x == u)break;
 62         }
 63     }
 64 }
 65 void find_scc(int n){
 66     dfs_clock = scc_cnt = 0;
 67     for(int i = 1;i <= n;++i){
 68         if(!dfn[i])dfs(i);
 69     }
 70 }
 71 void spfa(int x){
 72     for(int i = 1;i <= scc_cnt;++i){
 73         d[i] = INF;
 74     }
 75     bool visit[maxn];
 76     memset(visit,false,sizeof(visit));
 77     d[x] = 0;
 78     queue<int>q;
 79     q.push(x);
 80     visit[x] = true;
 81     while(!q.empty()){
 82         int y = q.front();
 83         q.pop();visit[y] = false;
 84         for(int i = h[y];i != -1;i = qmap[i].next){
 85             edges e = qmap[i];
 86             if(d[y] + e.cost < d[e.to]){
 87                 d[e.to] = d[y] + e.cost;
 88                 if(!visit[e.to]){
 89                     q.push(e.to);
 90                     visit[e.to] = true;
 91                 }
 92             }
 93         }
 94     }
 95 }
 96 void work(int i){
 97     spfa(i);
 98     for(int k = 1;k <= scc_cnt;++k){
 99         if(k == i)continue;
100         if(d[k] == INF)continue;
101         size[i] += sccno[k];
102     }
103     if(size[i] == n){
104         b = 1;
105         for(int j = 1;j <= n;++j){
106             if(ind[j] == i)printf("%d ",j);
107         }
108         printf("\n");
109     }
110     return;
111 }
112 int main(){
113     scanf("%d%d",&n,&m);
114     init(n);
115     for(int i = 1;i <= m;++i){
116         scanf("%d%d",&a,&b);
117         g[a].push_back(b);
118         gk[b].push_back(a);
119         ga.push_back(edge(b,a));
120     }
121     find_scc(n);
122     int ans = scc_cnt;
123     for(int i = 1;i <= scc_cnt;++i){
124         if(sccno[i] == 1)ans--;
125     }
126     printf("%d\n",ans);
127     for(int i = 0;i < ga.size();++i){
128         add(ind[ga[i].u],ind[ga[i].v]);
129     }
130     for(int i = 1;i <= scc_cnt;++i){
131         size[i] = sccno[i];
132     }
133     b = 0;
134     for(int i = 1;i <= scc_cnt;++i){
135         if(sccno[i] != 1)work(i);
136     }
137     if(b == 0)printf("-1\n");
138     return 0;
139 }

这次的解题报告就到这里,蒟蒻继续去刷题了。还有如果有问题的话,请联系我的邮箱PC-worker@outlook.com向我留言。

转载于:https://www.cnblogs.com/gangding/p/5657329.html

习题:codevs 2822 爱在心中 解题报告相关推荐

  1. Wikioi 2822爱在心中(强连通缩点+dfs)

    2822 爱在心中(强连通缩点+遍历) 2822 爱在心中 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 题目描述 Description " ...

  2. Codevs 2822 爱在心中

    http://codevs.cn/problem/2822/ 思路 Tarjin算法找出图中所有的节点数>1的环即爱心天使,将每个爱心天使缩成一个点,重新建图,在新图中找到一个入度为0的点(至多 ...

  3. 21行代码AC——习题3-7 DNA序列(UVa-1368)_解题报告

    励志用尽量少的代码做高效表达. 题目(提交)链接→UVa-1368 思路: DNA序列:按列遍历,记录每一列出现次数最多(若同样多,则字典序最小)的字母,录入s串累加. 距离:重新遍历,录入出现次数比 ...

  4. 26行代码AC——习题3-2 分子量 (UVa1586,Molar Mass)——解题报告

    大意: 给出分子式,式中只包含以下四种元素.求分子量. C:12.01 H: 1.008 O: 16.00 N: 14.01 Sample Input 4 C C6H5OH NH2CH2COOH C1 ...

  5. 19行代码AC——习题3-4 周期串(UVa-455)_解题报告

    励志用尽量少的代码做高效表达 题目(提交)链接-->UVa-455 题意: 输入一个长度不超过80的字符串,输出其最小周期. 思路: 本题的最佳思路是取余构造循环串求最小周期 按照正常求周期的方 ...

  6. 连飞学长的爱 解题报告 Apare_xzc

    连飞学长的爱 解题报告 2019/2/22 vj链接 A-A CodeForces - 560A 题意: 有一套纸币,有n个币种,问是否能构成任意面值? input: n a1 a2 - an 数据范 ...

  7. 解题报告(十八)数论题目泛做(Codeforces 难度:2000 ~ 3000 + )

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量的题解和代码,题目难度不一 ...

  8. uscao 线段树成段更新操作及Lazy思想(POJ3468解题报告)

    线段树成段更新操作及Lazy思想(POJ3468解题报告) 标签: treequerybuildn2cstruct 2011-11-03 20:37 5756人阅读 评论(0) 收藏 举报  分类: ...

  9. 解题报告(三)多项式求值与插值(拉格朗日插值)(ACM / OI)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量的题解和代码,题目难度不一 ...

最新文章

  1. keras提取模型中的某一层_keras获得某一层或者某层权重的输出实例
  2. 用vs2010编译vigra静态库及简单使用举例
  3. APRILTAG 标准图片:TAG25H9
  4. oozie捕获标准输出异常capture-output
  5. 无聊的python课程_无聊的钢镚的python学习之路
  6. DataStage8.7连接远程Oracle数据库
  7. 树莓派小车(远程控制、PWM变速、超声波自动避障)
  8. ospf实验及原理(ensp)
  9. linux打开u盘里的文件,Linux下U盘内容为只读文件不能存储其他内容的解决办法
  10. 原地怠速油耗最大吗?为什么有人说汽车宁可跑起来也不要原地怠速?
  11. SQL语句 获取系统日期
  12. 友盟分享Title设置
  13. word打开wps文件乱码_word文件打不开,打开时遇到错误用文本修复器打开文件 WPS打开时是乱码...
  14. c语言常用英语带音标,C语言常见英语单词,带音标
  15. Secondary NameNode工作机制
  16. OSChina 新年乱弹 ——爱你们,新年快乐
  17. 思科模拟器 --- 扩展IP访问控制列表配置
  18. python画饼图柱状图_荐【python数据分析(24)】Matplotlib库基本图形绘制(1)(线形图、柱状图、堆叠图、面积图、填图、饼图)...
  19. scaner 从外网到内网域渗透
  20. 实现不同的导航条,看直播app开发怎么做

热门文章

  1. 关于struts1的配置
  2. 谷歌Nexus 3开售时间曝光
  3. 雷林鹏分享:PHP 魔术常量
  4. 【leetcode】486. Predict the Winner
  5. flutter 安装遇坑记录
  6. Unity3D手机斗地主游戏开发实战(03)_地主牌显示和出牌逻辑
  7. Unity 打包发布Android新手教学 (小白都能看懂的教学 ) [转]
  8. 简单快速的开发WEB应用, PHP 框架 Lemon 介绍
  9. Apache常用配置
  10. 自定义PointViewPager依赖库