1.至少添加几条边,使有向图边成强连通图
思路:将有向图求强连通分量(SCC),缩点后变成有向无环图(DAG)!根据缩点后的新图,分别统计入度为0的结点个数(假设有a个),出度为0的结点个数(假设有b个)! 则max(a,b)就是答案!
注:这里的结点指得是缩点后的结点,即对应原图的一个强连通分量
例题:http://acm.hdu.edu.cn/showproblem.php?pid=2767
2.至少添加几条边,使无向图边成双连通图
思路:将无向图求双连通分量(BCC),缩点后变成一棵树!根据缩点后的新图,统计度为1的结点(假设有a个)! 则 (a+1)/2 就是答案!
例题:http://poj.org/problem?id=3177
3.给定一个有向图,问有多少个点由任意顶点出发都能到达
思路:将有向图求强连通分量(SCC),缩点后变成有向无环图(DAG)!统计新图中入度为0的结点个数,如果只有一个则输出该结点所代表的强连通分量下的顶点个数!否则无解,输出0!
注:DAG是个神奇的图!具备以下几点性质
1.任何DAG都有一个始点(我们假定入度为0的结点为始点,出度为0的结点为终点)
2.如果一个有向图的DAG只有一个始点,则由该始点出发可以到达DAG中的任意结点
3.如果一个有向图的DAG只有一个终点,则由图中的任意结点都可以到达这个终点
4.。。。。。。。
例题:http://poj.org/problem?id=2186
4.给定一个有向图,求出sink点 (sink点: 如果v能够到的点,反过来可以到达v点) 并按升序输出
思路:将有向图求强连通分量(SCC),缩点后变成有向无环图(DAG)!统计出度为0的结点个数,升序输出该结点所代表的强连通分量下的顶点
例题:http://poj.org/problem?id=2553
tarjan算法模版:
# include<cstdio>
# include<cstring>
# include<stack>
# include<algorithm>
using namespace std;
const int maxn=5005;
const int maxm=250005;
struct node
{
int u,v,next;
}e[maxm];
int num,head[maxn];
int low[maxn],dfn[maxn],idx[maxn],cnt,scc;
stack<int> s;
void addedge(int u,int v)
{
e[num].u=u;
e[num].v=v;
e[num].next=head[u];
head[u]=num++;
}
void tarjan(int u)
{
int i,v;
s.push(u);
dfn[u]=low[u]=cnt++;
for(i=head[u];i!=-1;i=e[i].next)
{
v=e[i].v;
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(!idx[v])
low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u])
{
scc++;
while(1)
{
v=s.top();
s.pop();
idx[v]=scc;
if(v==u)
break;
}
}
}
void init()
{
num=0;
memset(head,-1,sizeof(head));
scc=0;
cnt=1;
memset(dfn,0,sizeof(dfn));
memset(idx,0,sizeof(idx));
}