习题:codevs 2822 爱在心中 解题报告
这次的解题报告是有关tarjan算法的一道思维量比较大的题目(真的是原创文章,希望管理员不要再把文章移出首页)。
这道题蒟蒻以前做过,但是今天由于要复习tarjan算法,于是就看到codevs分类强联通分量里面只有这一道题。
题目是这样的:
“每个人都拥有一个梦,即使彼此不相同,能够与你分享,无论失败成功都会感动。爱因为在心中,平凡而不平庸,世界就像迷宫,却又让我们此刻相逢Our Home。” 在爱的国度里有N个人,在他们的心中都有着一个爱的名单,上面记载着他所爱的人(不会出现自爱的情况)。爱是具有传递性的,即如果A爱B,B爱C,则A也爱C。
如果有这样一部分人,他们彼此都相爱,则他们就超越了一切的限制,用集体的爱化身成为一个爱心天使。
现在,我们想知道在这个爱的国度里会出现多少爱心天使。而且,如果某个爱心天使被其他所有人或爱心天使所爱则请输出这个爱心天使是由哪些人构成的,否则输出-。
这是一个有向图上的问题,这道题很容易看出来一个爱心天使就是一群人互相爱然后组成的有向环。既然是有向的图求强联通分量,套上tarjan就行了。不过因为后面要输出爱心天使是由哪些人构成的,所以,我们需要记录每个人在哪个爱心天使里面,具体tarjan标程就是下面这样:
void dfs(int u){
low[u] = dfn[u] = ++dfs_clock;
s.push(u);
for(int i = ;i < g[u].size();++i){
int v = g[u][i];
if(!dfn[v]){
dfs(v);
low[u] = min(low[u],low[v]);
}
else if(!ind[v]){
low[u] = min(low[u],dfn[v]);
}
}
if(low[u] == dfn[u]){
scc_cnt++;
while(){
int x = s.top();
s.pop();
ind[x] = scc_cnt;
sccno[scc_cnt]++;
if(x == u)break;
}
}
}
void find_scc(int n){
dfs_clock = scc_cnt = ;
for(int i = ;i <= n;++i){
if(!dfn[i])dfs(i);
}
}
如果有不懂的地方,就说明是tarjan算法还是没搞懂,请先搞定tarjan算法的基础再来看这道题。
然后就是求每个爱心天使被多少个人爱着(爱心天使也被属于它自己的人们爱着)。由于爱有传递性,我们很容易能想到传递闭包的问题。具体做法就是:
1.先求出来所有的爱心天使(在这里一个人也当作是一个爱心天使,但是输出爱心天使个数的时候,一个人组成的爱心天使是不算的)和这个爱心天使由多少个人组成。
2.给每个爱心天使编号(缩点),然后建立一个以“被爱”为方向的新的有向图。
3.在新的有向图中跑SPFA(为什么不用Floyd,这个时间复杂度太高了,所以我们还是选择scc_cnt遍的SPFA,时间复杂度最坏也就是O(nke),保证是超不了时间的。SPFA在这里起到的作用就是计算每个爱心天使的爱能否传递到某个天使)。
4.统计计数,如果size[某个爱心天使] == n的话,那么就按编号从小到大遍历每个人输出这个爱心天使由哪些人组成。如果没有任何一个爱心天使的size为n的话,(用一个数记录,如果b == 0)就输出-1.
然后呈现整体代码,还是不是很长,才刚139行。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <set>
#include <queue>
using namespace std;
const int maxn = ;
int dfn[maxn],low[maxn],dfs_clock,n,ind[maxn],m,scc_cnt,a,b,size[maxn],sccno[maxn],tim = ;
struct edge{
int u,v;
edge(int a,int b):u(a),v(b){};
};
struct edges{
int to,next,cost;
}qmap[maxn<<];
vector<int>g[maxn];
vector<int>gk[maxn];
vector<edge>ga;
int d[maxn],h[maxn];
const int INF = ;
stack<int> s;
void add(int u,int v){
qmap[tim].to = v;qmap[tim].cost = ;qmap[tim].next = h[u];h[u] = tim++;
}
void init(int n){
memset(dfn,,sizeof(dfn));
memset(low,,sizeof(low));
memset(ind,,sizeof(ind));
memset(size,,sizeof(size));
memset(sccno,,sizeof(sccno));
memset(h,-,sizeof(h));
for(int i = ;i <= n;++i){
g[i].clear();
gk[i].clear();
}
}
void dfs(int u){
low[u] = dfn[u] = ++dfs_clock;
s.push(u);
for(int i = ;i < g[u].size();++i){
int v = g[u][i];
if(!dfn[v]){
dfs(v);
low[u] = min(low[u],low[v]);
}
else if(!ind[v]){
low[u] = min(low[u],dfn[v]);
}
}
if(low[u] == dfn[u]){
scc_cnt++;
while(){
int x = s.top();
s.pop();
ind[x] = scc_cnt;
sccno[scc_cnt]++;
if(x == u)break;
}
}
}
void find_scc(int n){
dfs_clock = scc_cnt = ;
for(int i = ;i <= n;++i){
if(!dfn[i])dfs(i);
}
}
void spfa(int x){
for(int i = ;i <= scc_cnt;++i){
d[i] = INF;
}
bool visit[maxn];
memset(visit,false,sizeof(visit));
d[x] = ;
queue<int>q;
q.push(x);
visit[x] = true;
while(!q.empty()){
int y = q.front();
q.pop();visit[y] = false;
for(int i = h[y];i != -;i = qmap[i].next){
edges e = qmap[i];
if(d[y] + e.cost < d[e.to]){
d[e.to] = d[y] + e.cost;
if(!visit[e.to]){
q.push(e.to);
visit[e.to] = true;
}
}
}
}
}
void work(int i){
spfa(i);
for(int k = ;k <= scc_cnt;++k){
if(k == i)continue;
if(d[k] == INF)continue;
size[i] += sccno[k];
}
if(size[i] == n){
b = ;
for(int j = ;j <= n;++j){
if(ind[j] == i)printf("%d ",j);
}
printf("\n");
}
return;
}
int main(){
scanf("%d%d",&n,&m);
init(n);
for(int i = ;i <= m;++i){
scanf("%d%d",&a,&b);
g[a].push_back(b);
gk[b].push_back(a);
ga.push_back(edge(b,a));
}
find_scc(n);
int ans = scc_cnt;
for(int i = ;i <= scc_cnt;++i){
if(sccno[i] == )ans--;
}
printf("%d\n",ans);
for(int i = ;i < ga.size();++i){
add(ind[ga[i].u],ind[ga[i].v]);
}
for(int i = ;i <= scc_cnt;++i){
size[i] = sccno[i];
}
b = ;
for(int i = ;i <= scc_cnt;++i){
if(sccno[i] != )work(i);
}
if(b == )printf("-1\n");
return ;
}
这次的解题报告就到这里,蒟蒻继续去刷题了。还有如果有问题的话,请联系我的邮箱PC-worker@outlook.com向我留言。
习题:codevs 2822 爱在心中 解题报告的更多相关文章
- 【CodeVS】2822 爱在心中 [2017年6月计划 强连通分量03]
2822 爱在心中 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description “每个人都拥有一个梦,即使彼此不相同,能够 ...
- codevs & vijos 爱在心中 - Tarjan
描述 “每个人都拥有一个梦,即使彼此不相同,能够与你分享,无论失败成功都会感动.爱因为在心中,平凡而不平庸,世界就像迷宫,却又让我们此刻相逢Our Home.” 在爱的国度里有N个人,在他们的心中都有 ...
- codevs 2822 爱在心中
codevs 2822 爱在心中 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description “每个人都拥有一个梦,即使彼此不相同, ...
- codevs——2822 爱在心中
2822 爱在心中 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 题目描述 Description “每个人都拥有一个梦,即使彼此不相 ...
- codevs 2822爱在心中
不想吐槽题目.... /* K bulabula 算法(好像用哪个T bulabula更简单 然而我并不会 - -) 丑陋的处理cnt: Printf时 cnt中 ans[i][0]==1 的删掉 然 ...
- BZOJ 1051 最受欢迎的牛 解题报告
题目直接摆在这里! 1051: [HAOI2006]受欢迎的牛 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4438 Solved: 2353[S ...
- 习题:codevs 1035 火车停留解题报告
本蒟蒻又来写解题报告了.这次的题目是codevs 1035 火车停留. 题目大意就是给m个火车的到达时间.停留时间和车载货物的价值,车站有n个车道,而火车停留一次车站就会从车载货物价值中获得1%的利润 ...
- 习题: codevs 2492 上帝造题的七分钟2 解题报告
这道题是受到大犇MagHSK的启发我才得以想出来的,蒟蒻觉得自己的代码跟MagHSK大犇的代码完全比不上,所以这里蒟蒻就套用了MagHSK大犇的代码(大家可以关注下我的博客,友情链接就是大犇MagHS ...
- 习题:codevs 1519 过路费 解题报告
今天拿了这道题目练练手,感觉自己代码能力又增强了不少: 我的思路跟别人可能不一样. 首先我们很容易就能看出,我们需要的边就是最小生成树算法kruskal算法求出来的边,其余的边都可以删掉,于是就有了这 ...
随机推荐
- Atitit usrqbg1821 Tls 线程本地存储(ThreadLocal Storage 规范标准化草案解决方案ThreadStatic
Atitit usrqbg1821 Tls 线程本地存储(ThreadLocal Storage 规范标准化草案解决方案ThreadStatic 1.1. ThreadLocal 设计模式1 1.2. ...
- java 线程协作 join()
在实际开发中我们往往会遇到这样的情况一个线程的执行需要依赖另一个线程执行后的结果.即主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他 ...
- Python数据类型之“集合(Sets)与映射(Mapping)”
一.集合类型(Sets) 集合对象是不同的(不可重复)hashable对象的无序集合.常见用法包括:成员关系测试.移除序列中的重复.以及科学计算,例如交集.并集.差分和对称差分.通俗点来说,集合是一个 ...
- dubbo+zookeeper简单环境搭建
dubbo+zoopeeper例子 [TOC] 标签(空格分隔): 分布式 dubbo dubbo相关 dubbo是目前国内比较流行的一种分布式服务治理方案.还有一种就是esb了.一般采用的是基于Ap ...
- JS面向对象逆向学习法,让难理解的统统一边去(1)~
对于面向对象我只能说呵呵了,为什么呢,因为没对象--- 既然你看到了这里,说明你有一定的基础,虽然本系列文章并不会过多的讲述基础部分,请做好心理准备. 本篇比较简单,这篇文章的意义是让你明白学习面向对 ...
- dubbox
github源码: https://github.com/dangdangdotcom/dubbox maven中央仓: 无 获取分支 git clone -b dubbox-2.8.4 https: ...
- PHP 对象 “==” 与 “===”
php中对象在内存中的存储方式与java等其他面向对象语言类似,$a = new Person();在内存中表现为$a是堆区中new Person()中的引用 这样当: $a = new Person ...
- 自制jquery可编辑的下拉框
昨天看到QQ登录的时候,可以选择以前登录过的账户,这个东西也可以在网站登录的时候用到,所以我就想做一个这样的插件:在网上查了很多,没有找到合适自己的,所以决定自动制作一个. 原理就是一个textbox ...
- 20个漂亮 CSS3 按钮效果及优秀的制作教程
在这篇文章中,我们编译了一组有用的 CSS3 动画按钮教程和引人注目的实验.正如我们都知道的,CSS3在网页设计方面是最重要和最关键的,可以使您的网站对访客更具吸引力和互动性.你可以学习这些教程和试验 ...
- Azure Automation (4) 按照Azure虚拟机的机器名,设置开关机
<Windows Azure Platform 系列文章目录> 本文介绍的是国内由世纪互联运维的Azure China服务. 在有的时候,我们不需要将所有的虚拟机进行开关机. 本文介绍的脚 ...