Describe:

  求一个有向图加多少条边可以变成一个强连通图

Solution:

  Tarjan缩点染色后,判断出度和入度,所有点的出度 = 0 的和 和 入度 = 0 的和的最大值即为所求。

缩点染色

for(int i = 1;i <= n;++i)
{
if(!dfn[i])
{
tarjan(i);
}
}
void tarjan(int s)
{
dfn[s] = low[s] = ++tot;
stk[stk_siz++] = s;
instk[s] = true; for(int i = id[s];~i;i = e[i].pre)
{
int to = e[i].to;
if(!dfn[to])
{
tarjan(to);
low[s] = min(low[s],low[to]);
}
else if(instk[to])
low[s] = min(low[s],dfn[to]);
}
if(dfn[s] == low[s])
{
++colid;
while(stk_siz > 0 && stk[stk_siz] != s)
{
--stk_siz;
int tmp = stk[stk_siz];
instk[tmp] = false;
col[tmp] = colid;
}
}
}

进行每一个缩点后的出度入度判断

for(int i = 0;i < m;++i)
{
from = e[i].from;
to = e[i].to;
//咋忘了缩点了!!这是缩点后的操作
// cout<<from<<" "<<to<<endl;
// cout<<col[from]<<" "<<col[to]<<endl;
if(col[from] != col[to])
{
in[col[to]]++;
out[col[from]]++;
}
}
int ret = 0,innum = 0,outnum = 0;
for(int i = 1;i <= colid;++i)
{
if(!in[i])innum++;
if(!out[i])outnum++;
}
ret = max(innum,outnum);

还要注意的就是缩成一个点的时候,也就是本来就是一个强连通分量是不需要添加边的

Coding:

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn = 2e4 + 1e3;
const int maxm = 5e4 + 1e3;
struct node{
int from,to,pre;
node(){}
node(int to,int pre):to(to),pre(pre){}
}e[maxm];
int colid;
int id[maxn],cnt;
int col[maxn];
int in[maxn],out[maxn];
int dfn[maxn],low[maxn];
int tot;
int stk[maxn],stk_siz; bool instk[maxn];
void add(int from,int to)
{
e[cnt].to = to;
e[cnt].from = from;
e[cnt].pre = id[from];
id[from] = cnt++;
}
void init()
{
memset(id,-1,sizeof(id));
memset(instk,0,sizeof(instk));
memset(dfn,0,sizeof(dfn));
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
cnt = tot = colid = stk_siz = 0;
}
void tarjan(int s)
{
dfn[s] = low[s] = ++tot;
stk[stk_siz++] = s;
instk[s] = true; for(int i = id[s];~i;i = e[i].pre)
{
int to = e[i].to;
if(!dfn[to])
{
tarjan(to);
low[s] = min(low[s],low[to]);
}
else if(instk[to])
low[s] = min(low[s],dfn[to]);
}
if(dfn[s] == low[s])
{
++colid;
while(stk_siz > 0 && stk[stk_siz] != s)
{
--stk_siz;
int tmp = stk[stk_siz];
instk[tmp] = false;
col[tmp] = colid;
}
}
}
int main()
{
int t,n,m;
scanf("%d",&t);
while(t--)
{
init();
scanf("%d%d",&n,&m);
int from,to;
for(int i = 1;i <= m;++i)
{
scanf("%d%d",&from,&to);
add(from,to);
}
for(int i = 1;i <= n;++i)
{
if(!dfn[i])
{
tarjan(i);
}
}
//边的存储是从1开始!!
for(int i = 0;i < m;++i)
{
from = e[i].from;
to = e[i].to;
//咋忘了缩点了!!这是缩点后的操作
// cout<<from<<" "<<to<<endl;
// cout<<col[from]<<" "<<col[to]<<endl;
if(col[from] != col[to])
{
in[col[to]]++;
out[col[from]]++;
}
}
int ret = 0,innum = 0,outnum = 0;
for(int i = 1;i <= colid;++i)
{
if(!in[i])innum++;
if(!out[i])outnum++;
}
ret = max(innum,outnum);
//特殊判断一下,一个点的时候(一种颜色的时候就是强连通了)
if(colid == 1)
printf("%d\n",0);
else
printf("%d\n",ret);
}
return 0;
}

  

Tarjan求缩点化强连通图的更多相关文章

  1. 【BZOJ3331】[BeiJing2013]压力 Tarjan求点双

    [BZOJ3331][BeiJing2013]压力 Description 如今,路由器和交换机构建起了互联网的骨架.处在互联网的骨干位置的核心路由器典型的要处理100Gbit/s的网络流量.他们每天 ...

  2. tarjan求强连通分量+缩点+割点以及一些证明

    “tarjan陪伴强联通分量 生成树完成后思路才闪光 欧拉跑过的七桥古塘 让你 心驰神往”----<膜你抄>   自从听完这首歌,我就对tarjan开始心驰神往了,不过由于之前水平不足,一 ...

  3. tarjan求强连通分量+缩点+割点/割桥(点双/边双)以及一些证明

    “tarjan陪伴强联通分量 生成树完成后思路才闪光 欧拉跑过的七桥古塘 让你 心驰神往”----<膜你抄>   自从听完这首歌,我就对tarjan开始心驰神往了,不过由于之前水平不足,一 ...

  4. 连通分量模板:tarjan: 求割点 &amp;&amp; 桥 &amp;&amp; 缩点 &amp;&amp; 强连通分量 &amp;&amp; 双连通分量 &amp;&amp; LCA(近期公共祖先)

    PS:摘自一不知名的来自大神. 1.割点:若删掉某点后.原连通图分裂为多个子图.则称该点为割点. 2.割点集合:在一个无向连通图中,假设有一个顶点集合,删除这个顶点集合,以及这个集合中全部顶点相关联的 ...

  5. Tarjan求强连通分量,缩点,割点

    Tarjan算法是由美国著名计算机专家发明的,其主要特点就是可以求强连通分量和缩点·割点. 而强联通分量便是在一个图中如果有一个子图,且这个子图中所有的点都可以相互到达,这个子图便是一个强连通分量,并 ...

  6. HDU 1827 Summer Holiday(tarjan求强连通分量+缩点构成新图+统计入度+一点贪心思)经典缩点入门题

    Summer Holiday Time Limit: 10000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...

  7. Tarjan求强联通分量+缩点

    提到Tarjan算法就不得不提一提Tarjan这位老人家 Robert Tarjan,计算机科学家,以LCA.强连通分量等算法闻名.他拥有丰富的商业工作经验,1985年开始任教于普林斯顿大学.Tarj ...

  8. POJ 1236 Network of Schools (tarjan算法+缩点)

    思路:使用tarjan求强连通分量并进行缩点,判断所有入度为0的点,这个点就是必须要给予文件的点,分别计算出度,入度为零的点的个数,取二者的最大值就是把这个图变成强连通需要加的边数. 一个取值需要讨论 ...

  9. UESTC 901 方老师抢银行 --Tarjan求强连通分量

    思路:如果出现了一个强连通分量,那么走到这个点时一定会在强连通分量里的点全部走一遍,这样才能更大.所以我们首先用Tarjan跑一遍求出所有强连通分量,然后将强连通分量缩成点(用到栈)然后就变成了一个D ...

随机推荐

  1. 转easyui datagrid 前台分页的实现

    easyui datagrid 前台分页的实现java采用的版本 来源:本站原创 js知识 超过5,090人围观 暂无评论 使用easyui分页,有后台服务器端实现和前台浏览器端实现.服务器端实现按规 ...

  2. Eclipse中的maven项目搭建

    一.eclipse中的maven设置 1.打开“首选项”----> "maven"---->"Installations".用来查看maven的使用 ...

  3. Python pip下载安装库 临时用清华镜像命令

    pip install -i https://pypi.tuna.tsinghua.edu.cn/simple C:\Users\mu\pip 新建pip.ini [global] index-url ...

  4. mybatis 操作数据错误Truncated incorrect DOUBLE value: ''

    网上查到遇到次错误造成的原因: UPDATE TSYS_ROLE_RIGHTSET ACTIVE_FLAG = '2' and UPDATE_PERSON = 'CaiYiHua' and  UPDA ...

  5. easyui下拉框过滤优化

    项目中有个需求:编辑combobox的输入域会自动检索匹配项,当没有任何匹配项时,将combobox重置为初始状态. 处理方式:重写输入域的blur事件,判断当前值是否为加载的数据集的子集,如果不是则 ...

  6. 51nod1347 旋转字符串

    题目很容易懂,只要进行几次简单的判断就能完成此题,显示判断是否为偶数,之后利用sustr截取两个字符串进行比较,代码如下 #include<iostream> #include<st ...

  7. 【Linux】开机自动启动脚本

    Linux下(以RedHat为范本)添加开机开机自动启动脚本有两种方式; 本例系统:Linux(CentOS 7.2) 方法一 使用 /etc/rc.d/rc.local,自动启动脚本 #!/bin/ ...

  8. [C#]WinForm动态删除控件 Controls.Remove()

    今天遇到一个奇怪的问题,在WinForm内动态添加Button后再动态的移除,发生稀奇古怪的现象,Button控件只被规律的移除,没有完全移除 foreach (Control c in this.C ...

  9. css的基础用法之标签选择

    一.css的4种引入方式 #.内联式 <p style="color: red;font-size: 50px;text-align: center">Egon是一个非 ...

  10. oracle 分组中排序(rank函数)

    需求: 查询每个供应商在每个类型产品销售的top50中有多少 分析: 1.查询,以指定字段(供应商.产品类型)分组,取每个分组的前50行,查看每个供应商的数量 2.使用rank函数给每个供应商.每个类 ...