您的位置:首页 > 其它

POJ 1236 强联通

2014-01-22 21:50 141 查看
强连通分量缩点求入度为0的个数和出度为0的分量个数
题目大意:N(2<N<100)各学校之间有单向的网络,每个学校得到一套软件后,可以通过单向网络向周边的学校传输,问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。2,至少需要添加几条传输线路(边),使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件。

也就是:
给定一个有向图,求:

1) 至少要选几个顶点,才能做到从这些顶点出发,可以到达全部顶点

2) 至少要加多少条边,才能使得从任何一个顶点出发,都能到达全部顶点

顶点数<= 100
解题思路
1. 求出所有强连通分量
2. 每个强连通分量缩成一点,则形成一个有向无环图DAG。
3. DAG上面有多少个入度为0的顶点,问题1的答案就是多少
在DAG上要加几条边,才能使得DAG变成强连通的,问题2的答案就是多少
加边的方法
要为每个入度为0的点添加入边,为每个出度为0的点添加出边
假定有 n 个入度为0的点,m个出度为0的点,如何加边?
把所有入度为0的点编号 0,1,2,3,4 ....N -1
每次为一个编号为i的入度0点可达的出度0点,添加一条出边,连到编号为(i+1)%N 的那个出度0点,
这需要加n条边
若 m <= n,则
加了这n条边后,已经没有入度0点,则问题解决,一共加了n条边
若 m > n,则还有m-n个入度0点,则从这些点以外任取一点,和这些点都连上边,即可,这还需加m-n条边。
所以,max(m,n)就是第二个问题的解
此外:当只有一个强连通分支的时候,就是缩点后只有一个点,虽然入度出度为0的都有一个,但是实际上不需要增加清单的项了,所以答案是1,0;

#include<cstdio>
#include<stdlib.h>
#include<string.h>
#include<string>
#include<map>
#include<cmath>
#include<iostream>
#include <queue>
//#include <stack>
#include<algorithm>
#include<set>
using namespace std;
#define INF 1e8
#define eps 1e-8
#define LL __int64
#define maxn 26
#define mol 1000000007
#define N 1010
#define M 100001
struct Edge
{
int v;
int next;
};
Edge edge[M];//边的集合

int node
;//顶点集合
int instack
;//标记是否在stack中
int stack
;
int Belong
;//各顶点属于哪个强连通分量
int DFN
;//节点u搜索的序号(时间戳)
int LOW
;//u或u的子树能够追溯到的最早的栈中节点的序号(时间戳)
int n, m;//n:点的个数;m:边的条数
int cnt_edge;//边的计数器
int Index;//序号(时间戳)
int top;
int Bcnt;//有多少个强连通分量
int in
,out
,numd
;
void add_edge(int u, int v)//邻接表存储
{
edge[cnt_edge].next = node[u];
edge[cnt_edge].v = v;
node[u] = cnt_edge++;
}
void tarjan(int u)
{
int i, j;
int v;
DFN[u] = LOW[u] = ++Index;
instack[u] = true;
stack[++top] = u;
for (i = node[u]; i != -1; i = edge[i].next)
{
v = edge[i].v;
if (!DFN[v])//如果点v没被访问//树枝边
{
tarjan(v);
if (LOW[v]<LOW[u])
LOW[u] = LOW[v];
}
else//如果点v已经被访问过//后向边
if (instack[v] && DFN[v]<LOW[u])
LOW[u] = DFN[v];
}
if (DFN[u] == LOW[u])//缩点
{
Bcnt++;
do
{
j = stack[top--];
instack[j] = false;
Belong[j] = Bcnt;
} while (j != u);
}
}
void solve()
{
int i;
top = Bcnt = Index = 0;
memset(DFN, 0, sizeof(DFN));
memset(LOW, 0, sizeof(LOW));
memset(Belong, 0, sizeof(Belong));
for (i = 1; i <= n; i++)
if (!DFN[i])
tarjan(i);
}
int main()
{
//freopen("in.txt", "r", stdin);
int i, j, k, t;
scanf("%d", &n);
cnt_edge = 0;
memset(node, -1, sizeof(node));

for (i = 1; i <= n; i++)
{
while(1)
{
scanf("%d", &j);
if(!j) break;
add_edge(i,j);
}
}
solve();
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
memset(numd,0,sizeof(numd));
for(i=1;i<=n;i++)
{
for(j=node[i];j!=-1;j=edge[j].next )
{
if(Belong[i]!=Belong[edge[j].v])
{
in[Belong[edge[j].v]]++;
out[Belong[i]]++;
}
}
}
int a=0,b=0;
for(i=1;i<=Bcnt;i++)
{
if(!in[i])
a++;
if(!out[i])
b++;
}

if(Bcnt==1) printf("1\n0\n");
else
printf("%d\n%d\n",a,max(a,b));
//printf("%d\n",max(a,b));

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: