在图中求双联通和强联通分量是我们解决非树结构的图连通问题的利器

通过求求图的双联通和强联通分量能把图转化成DAG进行求解;

行走

Description

给出一个有向图,你可以选择从任意点出发走到任意点结束,问最多可以经过多少个点(重复经过只算一次)。

Input Format

第一行,两个整数,n和m。表示有向图的点数和边数。

接下来是m行每行输入两个数a,b,表示有一条从a到b的路。

Output Format

输出最多可以经过的点数

Sample Input

10 10
6 4
0 8
5 9
8 1
7 7
4 8
5 9
7 5
9 5
7 7

Sample Output

4

Hint

对于30%的数据,1≤n,m≤10

对于100%的数据,1≤n,m≤10000,0≤a,b

题目不保证图是拓扑结构(DAG)那么就有可能出现自环枚举每个点搜图效率慢T(n(m+n));

暴力算法明显超时 这时求强联通分量进行缩点就派上用场;

若把图转成DAG那么就可以通过每颗树的根节点搜索图 进行统计了T(n+m)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#define maxn 100010
using namespace std;
int n,m,i,j,k,top,tim,t,co,ans;
struct st{int nex,to;}mu[2*maxn];
int s[maxn],pre[maxn],low[maxn],last[maxn],bcc[maxn],xx[maxn],yy[maxn],sum[maxn],bo[maxn];
int dfs(int u)
{
int v;
s[++top]=u;
low[u]=pre[u]=++tim;
for(int z=last[u];z;z=mu[z].nex)
{
v=mu[z].to;
if(!pre[v])
{
dfs(v);
low[u]=min(low[u],low[v]);
}
else if(!bo[v])
low[u]=min(low[u],pre[v]);
}
if(low[u]==pre[u])
{
++co;
int num=0;
for(; ;)
{
num++;
bo[s[top]]=co;
bcc[s[top--]]=co;
if(s[top+1]==u)break;
}
sum[co]=num;
}
return low[u];
}
void dfs1(int u)
{
low[u]=sum[u];
int p=0;
for(int z=last[u];z;z=mu[z].nex)
{
if(!low[mu[z].to])
dfs1(mu[z].to);
p=max(p,low[mu[z].to]);
}
low[u]+=p;
}
int main()
{
// freopen("xx.in","r",stdin);
scanf("%d%d",&n,&m);
for(i=1;i<=m;++i)
{
int u,v;
scanf("%d%d",&xx[i],&yy[i]);
t++;mu[t].nex=last[xx[i]];
mu[t].to=yy[i];last[xx[i]]=t;
}
for(i=0;i<n;++i)
if(!pre[i])
{
tim=0;top=0;dfs(i);
}
for(i=0;i<=co;++i)
low[i]=s[i]=last[i]=0;t=0;
for(i=1;i<=m;++i)
{
int u=bcc[xx[i]],v=bcc[yy[i]];
if(u==v)continue;
t++;mu[t].nex=last[u];
mu[t].to=v;last[u]=t;s[v]++;
}
for(i=1;i<=co;++i)
if(!s[i])
{
dfs1(i);
ans=max(ans,low[i]);
}
printf("%d",ans);
}

间谍网络

Description

由于外国间谍的大量渗入,国家安全正处于高度的危机之中。如果A间谍手中掌握着关于B间谍的犯罪证据,则称A可以揭发B。有些间谍收受贿赂,只要给他们一定数量的美元,他们就愿意交出手中掌握的全部情报。所以,如果我们能够收买一些间谍的话,我们就可能控制间谍网中的每一分子。因为一旦我们逮捕了一个间谍,他手中掌握的情报都将归我们所有,这样就有可能逮捕新的间谍,掌握新的情报。

我们的反间谍机关提供了一份资料,色括所有已知的受贿的间谍,以及他们愿意收受的具体数额。同时我们还知道哪些间谍手中具体掌握了哪些间谍的资料。假设总共有n个间谍(n不超过3000),每个间谍分别用1到3000的整数来标识。

请根据这份资料,判断我们是否有可能控制全部的间谍,如果可以,求出我们所需要支付的最少资金。否则,输出不能被控制的一个间谍。

Input Format

输入文件age.in第一行只有一个整数n。

第二行是整数p。表示愿意被收买的人数,1≤p≤n。

接下来的p行,每行有两个整数,第一个数是一个愿意被收买的间谍的编号,第二个数表示他将会被收买的数额。这个数额不超过20000。

紧跟着一行只有一个整数r,1≤r≤8000。然后r行,每行两个正整数,表示数对(A, B),A间谍掌握B间谍的证据。

Output Format

如果可以控制所有间谍,第一行输出YES,并在第二行输出所需要支付的贿金最小值。否则输出NO,并在第二行输出不能控制的间谍中,编号最小的间谍编号。

Sample Input

【样例1】
age.in
3
2
1 10
2 100
2
1 3
2 3 【样例2】
age.in
4
2
1 100
4 200
2
1 2
3 4

Sample Output

【样例1】
YES
110 【样例2】
NO
3
如果间谍网出现强联通分量那么只要其中一个能被收买就能逮捕强联通分量内的所有间谍(只收买最便宜的间谍);
那么就求强联通进行缩点 ;然后只要收买树根的间谍就行了;
为什么? 因为你要收买所有间谍 树根的间谍一定要收买 那么一整棵树的间谍都被逮捕了;
只要每颗树的树根都能收买 那么一定能控制所有间谍;
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#define maxn 3010
using namespace std;
int n,i,j,k,l,m,p,co,tim,top,t,ans;
struct st{int nex,to;}mu[maxn*6];
int s[maxn],last[maxn],bcc[maxn],bo[maxn],pre[maxn],low[maxn],b[maxn],xx[maxn*3],yy[maxn*3];
int dfs(int u)
{
pre[u]=low[u]=++tim;
int v;s[++top]=u;
for(int z=last[u];z;z=mu[z].nex)
{
v=mu[z].to;
if(!pre[v])
{
dfs(v);
low[u]=min(low[u],low[v]);
}
else if(!b[maxn])
low[u]=min(low[u],pre[v]);
}
if(pre[u]==low[u])
{
++co;
for(; ;)
{
b[s[top]]=1;
bcc[s[top--]]=co;
if(s[top+1]==u)break;
}
}
}
void add(int x,int y)
{
t++;mu[t].nex=last[x];
mu[t].to=y;last[x]=t;
}
int main()
{
// freopen("xx.in","r",stdin);
scanf("%d%d",&n,&p);
for(i=1;i<=p;++i)
{
int u,v;
scanf("%d%d",&u,&v);
bo[u]=v+1;
}
scanf("%d",&m);
for(i=1;i<=m;++i)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
xx[i]=u;yy[i]=v;
}
for(i=1;i<=n;++i)
if(!pre[i])
{
top=tim=0;
dfs(i);
}
for(i=1;i<=co;low[i]=1e9,++i)s[i]=b[i]=0;
for(i=1;i<=m;++i)
{
if(bcc[xx[i]]==bcc[yy[i]])continue;
s[bcc[yy[i]]]=1;
}
for(i=1;i<=n;++i)
if(bo[i])
low[bcc[i]]=min(low[bcc[i]],bo[i]-1);
for(i=1;i<=co;++i)
if(!s[i])
{
if(low[i]==1e9)
{
for(j=1;j<=n;++j)
if(bcc[j]==i)break;
printf("NO\n%d",j);
return 0;
}
ans+=low[i];
}
printf("YES\n%d",ans);
}

 

Freda的迷宫

Description

Freda是一个迷宫爱好者,她利用业余时间建造了许多迷宫。每个迷宫都是由若干房间和走廊构成的,每条走廊都连接着两个不同的房间,两个房间之间最多只有一条走廊直接相连,走廊都是双向通过。

黄昏时候,Freda喜欢在迷宫当中漫步。每天,Resodo都会为Freda设计一个挑战方案。Resodo会指定起点和终点,请Freda来找到一条从起点到终点的简单路径。一条简单路径定义为一个房间序列,每个房间至多在序列里出现一次,且序列中相邻的两个房间有走廊相连。当起点和终点之间存在且仅存在一条简单路径的时候,Freda认为这个挑战方案是RD的。现在,请你帮帮Resodo来写一个程序,判断一个挑战方案是否是RD的。

Input Format

第一行三个整数N,M,Q.分别表示房间数,走廊数,询问数。

接下来M行每行2个整数x,y, 0<=N, 表示x和y之间有一条走廊相连。

接下来Q行每行2个整数x,y, 表示询问以x为起点,y为终点的挑战方案是否是RD的.

Output Format

对于每个询问,输出一行”Y”或者”N”(不含引号).Y表示该询问所表示的挑战方案是RD的,N表示该询问所表示的挑战方案不是RD的.

Sample Input

6 5 3
1 2
2 3
2 4
2 5
4 5
1 3
1 5
2 6

Sample Output

Y
N
N

Hint

样例解释

1,3之间只有一条路径 1->2->3

1,5之间有两条路径 1->2->5 ; 1->2->4->5

1,6之间没有路径

数据范围与约定

对于30%的数据,N<=100, M<=1000, Q<=100.

对于50%的数据,N<=1000, M<=10000, Q<=1000.

对于100%的数据,N<=10000, M<=100000, Q<=10000.

按题意在线处理定会超时;

怎么做到离线算法?

首先有简单路径必须保证两点联通 且只有唯一路径;

那么这条路径一定由桥组成;那就可以保证路径唯一,且联通;

用Tarjan求桥;

将桥两端点归进一个集合 这时就要用到并查集了;

最后对于每个询问只要判断两点在同一集合就能保证有唯一路径;

#include<cstdio>
#include<iostream>
#define maxn 10010
using namespace std;
int n,t,i,j,k,l,m,q,tim,_bcc,_scc,top,fu,fv;
int last[maxn],bcc[maxn],scc[maxn],pre[maxn],low[maxn],f[maxn];
struct st{int nex,to;}mu[maxn*20];
void add(int x,int y)
{
t++;mu[t].nex=last[x];
mu[t].to=y;last[x]=t;
}
int gets(int x)
{return f[x]==x ? x:f[x]=gets(f[x]);}
int dfs(int u,int fa)
{
pre[u]=low[u]=++tim;
int v;
for(int z=last[u];z;z=mu[z].nex)
{
v=mu[z].to;
if(!pre[v])
{
dfs(v,u);
low[u]=min(low[u],low[v]);
if(pre[u]<low[v])
{
fu=gets(u);fv=gets(v);
if(fu!=fv)f[fv]=fu;
}
}
else if(pre[u]>pre[v]&v!=fa)
low[u]=min(pre[v],low[u]);
}
return low[u];
}
int main()
{
// freopen("xx.in","r",stdin);
scanf("%d%d%d",&n,&m,&q);
for(i=1;i<=m;++i)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
for(i=1;i<=n;++i)f[i]=i;
for(i=1;i<=n;++i)
if(!pre[i])
{
tim=0;top=0;
dfs(i,-1);
}
for(i=1;i<=q;++i)
{
int u,v;
scanf("%d%d",&u,&v);
u=gets(u);v=gets(v);
if(u==v)printf("Y\n");
else printf("N\n");
}
}

  

Tarjan 求图点强联通,桥的应用的更多相关文章

  1. POJ 1236--Network of Schools【scc缩点构图 &amp;&amp; 求scc入度为0的个数 &amp;&amp; 求最少加几条边使图变成强联通】

    Network of Schools Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 13325   Accepted: 53 ...

  2. Tarjan求割点(割顶) 割边(桥)

    割点的定义: 感性理解,所谓割点就是在无向连通图中去掉这个点和所有和这个点有关的边之后,原先连通的块就会相互分离变成至少两个分离的连通块的点. 举个例子: 图中的4号点就是割点,因为去掉4号点和有关边 ...

  3. HDU 4635 多校第四场 1004 强联通

    我还有什么好说,还有什么好说...... 我是SBSBSBSBSBSBSBSBSBSBSBSBBSBSBSBSBSBSBSBSBS........................ 题意 思路什么的都不 ...

  4. POJ 2186 Popular Cows(强联通分量)

    题目链接:http://poj.org/problem?id=2186 题目大意:    每一头牛的愿望就是变成一头最受欢迎的牛.现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎. 这 种 ...

  5. POJ 2762Going from u to v or from v to u?(强联通 + 缩点 + 拓扑排序)

    [题意]: 有N个房间,M条有向边,问能否毫无顾虑的随机选两个点x, y,使从①x到达y,或者,②从y到达x,一定至少有一条成立.注意是或者,不是且. [思路]: 先考虑,x->y或者y-> ...

  6. 【强联通分量缩点】【最长路】【spfa】CH Round #59 - OrzCC杯NOIP模拟赛day1 队爷的讲学计划

    10分算法:对于城市网络为一条单向链的数据, 20分算法:对于n<=20的数据,暴力搜出所有的可能路径. 结合以上可以得到30分. 60分算法:分析题意可得使者会带着去的城市也就是这个城市所在强 ...

  7. 校园网络 luogu P2812 (又是强联通)

    题目传送门!(luogu) 首先考虑问题一 不难想到,如果有一个学校作为终端机,那么跟其处于同一个强联通中的所有学校就可以不用作为终端机了. 那么,问题一也就迎刃而解了:找到所有入度为0的缩点.因为这 ...

  8. HDU 2767 Proving Equivalences (强联通)

    pid=2767">http://acm.hdu.edu.cn/showproblem.php?pid=2767 Proving Equivalences Time Limit: 40 ...

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

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

随机推荐

  1. HDL之Bitwise operation

    1 Verilog 1.1 Bitwise operator Bitwise operators perform a bit wise operation on two operands. They ...

  2. 组装自己的tesla超级计算机

    原文链接:blog.csdn.net/xqj198404/article/details/20016279 NVIDIA链接:http://www.nvidia.cn/object/tesla_bui ...

  3. 考考你对java多态的理解

    请看如下代码, 如果你能不运行得出正确答案, 那你真的超过99%的java程序员了. [本人属于最大头的那部分] public class A{ public String s = "A&q ...

  4. (转)shiro权限框架详解05-shiro授权

    http://blog.csdn.net/facekbook/article/details/54910606 本文介绍 授权流程 授权方式 授权测试 自定义授权realm 授权流程 开始构造Secu ...

  5. sql_2

    编辑表结构ALTER TABLE `sp_account_trans`     MODIFY COLUMN `TRANS_DESC` varchar(81) CHARACTER SET utf8 CO ...

  6. vc++如何创建程序--利用快捷键进行多行注释

    Eclipse同时注释多行①:ctrl+/或 ②:ctrl+shift+/ : Visual studio先按ctrl+k 再按 ctrl+c 2.在VC++6.0中需要自己设置快捷键,设置方法链接如 ...

  7. 洛谷P1231 教辅的组成 最大流

    裸题… Code: #include<cstdio> #include<cstring> #include<algorithm> #include<vecto ...

  8. 重置浏览器默认样式 normalize.css

    1 /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ /* Document ========= ...

  9. Laravel的维护模式

    1.开启维护模式:  php artisan down 2.关闭维护模式:php artisan up 3.当应用处于维护模式时,所有的路由都会指向一个自定义的视图.这对于更新应用或执行维护任务时临时 ...

  10. sessionStorage与clone方法在项目中的应用

    //资料列表: //JSON.parse(jsonstr); //json格式字符串转换成json对象 //JSON.stringify(jsonobj); //json对象转换成json格式字符串 ...