您的位置:首页 > 其它

POJ1236强连通分量tarjan

2012-04-24 14:04 330 查看
//题目大意:给定一个有向图,1.问最少可以从多少个点出发.访问完所有的点.  2.添加最少多少条边可以使得此图为一个强连通图
//解题思路:通过缩点.将该有向图变成一个类似于树的结构..在新的图中.存在一些入度为0和出度为0的特殊点..
//         对于问题1..要能够访问完所有的点..那些入度为0的点是不可能从别的点访问得到的..所以这些点必须从自身开始
//                    访问...同时.从这些入度为0的点开始访问以后.其他点入度均不为0,
//                    所以一定能够从这些点中找到一条路径访问该点
//         问题2..若要使得该图变成一个强连通图.那么入度为0的点和出度为0的点必须全部不存在.
//                那么最优的结果就是把入度为0的和出度为0的相连接..这样的结果就一定是max(num(出度为0),num(入度为0))
//                是否一定能够保证图强连通呢?  我们把入度为0的点称作根节点.出度为0的点称作叶子节点
//                那么每个叶子节点必然是由某个根节点出发得到的..而对于每个叶子节点..只要我们把它连出去的边
//                指向不是自己根节点的根节点的话..类似这样的情形
//                根节点1 --> 叶子节点1 . . 根节点2 --> 叶子节点2  根节点3 --> 叶子节点3
//                那么叶子节点1 --> 根节点2 . 就相当于把根节点1 叶子节点1 根节点2 叶子节点2 都连接起来了.
//                然后将 叶子节点2 --> 根节点3 .  叶子节点3 --> 根节点1 ..
//                这样以后..对于每个叶子节点 , 可以通过其他叶子节点的根到达该叶子节点..这样就可以使得每个
//                叶子节点和根节点都能够到达别的叶子节点和根节点.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<math.h>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
const int mn = 111;
int LOW[mn],DFN[mn],que[mn],po,visit,belong[mn],res[mn],t,out[mn],in[mn],father[mn],rank[mn];
bool intack[mn];
vector<int>tree[mn];
vector<int>ans[mn];
void Tarjan(int x)
{
LOW[x] = ++visit;
DFN[x] = LOW[x];
que[++po] = x;
intack[x] = 1;
for(int i = 0 ; i < tree[x].size() ; i++)
{
int m = tree[x][i];
if(!DFN[m])
{
Tarjan(m);
LOW[x] = min(LOW[x] , LOW[m]);
}
else if(intack[m])LOW[x] = min(LOW[x] , DFN[m]);
}
if(DFN[x] == LOW[x])
{
res[++t] = x;
int m;
do
{
m = que[po] ;
belong[m] = x;
po--;
intack[m] = 0;
}while(m != x);
}
}
void init(int m)
{
for(int i = 1 ; i <= m ; i++)
{
father[i] = i;
rank[i] = 0;
}
}
int find(int x)
{
if(x != father[x])
father[x] = find(father[x]);
return father[x];
}
void Union(int x , int y)
{
x = find(x);
y = find(y);
if(x == y)return ;
if(rank[x] > rank[y])father[y] = x;
else
{
if(rank[x] == rank[y])rank[y]++;
father[x] = y;
}
}
int n;
int main()
{
while(scanf("%d",&n) != EOF)
{
po = 0;visit = 0;t = 0;
memset(belong,0,sizeof(belong));
memset(que,0,sizeof(que));
memset(intack,0,sizeof(intack));
memset(DFN,0,sizeof(DFN));
memset(LOW,0,sizeof(LOW));
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
memset(res,0,sizeof(res));
init(n);
for(int i = 1 ; i <= n ; i++)
{
tree[i].clear();
ans[i].clear();
}
for(int i = 1 ; i <= n ; i++)
{
int x;
while(scanf("%d",&x) && x )
{
tree[i].push_back(x);
ans[x].push_back(i);
}
}
for(int i = 1 ; i <= n ; i++)
if(!DFN[i])Tarjan(i);
for(int i = 1 ; i <= n ; i++)
Union(i,belong[i]);
for(int i = 1 ; i <= n ; i++)
{
// printf("%d %d\n",i,belong[i]);
for(int j = 0 ; j < tree[i].size() ; j++)
if(find(i) != find(tree[i][j]))out[belong[i]] ++;
for(int j = 0 ; j < ans[i].size() ; j++)
if(find(i) != find(ans[i][j]))in[belong[i]] ++;
}
int ans1 = 0 , ans2= 0;
if(t == 1)printf("1\n0\n");
else
{

for(int i = 1 ; i <= t ; i++)
{
// printf("%d  %d  %d\n",res[i],in[res[i]],out[res[i]]);
if(!in[res[i]])ans1++;
if(!out[res[i]])ans2++;
}
printf("%d\n%d\n",ans1,max(ans1,ans2));
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: