您的位置:首页 > 其它

POJ 1236 Tarjan缩点+求度数

2012-04-17 12:52 519 查看
题目链接: http://poj.org/problem?id=1236

题目大意:

  给定一个n (n<=100)个点的有向图,问:
  Q1、最少需要选择多少个点,使得从这些点出发能遍历完整个图;
  Q2、最少需要添加多少条有向边,使得整个图成为连通图;

分析:

开始Q1我想复杂了,先说Q2吧,和hdu2767一样,当时我自己ac了hdu2767,可是做Q2的时候又一下没想到,便找出了原来的代码……

先由Tarjan算法求出强连通分量后进行缩点,得到每个强连通分量的入度in[],出度out[];

  Q1: 入度为0的强连通分量个数;

  Q2: max( 入度为0的强连通分量个数 , 出度为0的强连通分量个数 );

代码:

poj1236

/*1236    Accepted    264K    32MS    C++    2408B    2012-04-17 12:29:23*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

#define mpair make_pair
#define pii pair<int,int>
#define MM(a,b) memset(a,b,sizeof(a));
typedef long long lld;
typedef unsigned long long u64;
template<class T> bool up_max(T& a,const T& b){return b>a? a=b,1 : 0;}
template<class T> bool up_min(T& a,const T& b){return b<a? a=b,1 : 0;}
#define maxn 110

int n;
vector<int> adj[maxn];

bool vis[maxn];
int Bcnt, Top, Index;
int stack[maxn], low[maxn], dfn[maxn];
int belong[maxn];
void Init_tarjan(){
Bcnt= Top= Index= 0;
for(int i=1;i<=n;++i) low[i]= dfn[i]= vis[i]= 0;
}
void Tarjan(int u){
vis[u]= 1; /// push() into stack;
stack[++Top]= u;
low[u]= dfn[u]= ++Index;
for(int i=0;i<adj[u].size();++i){
int v= adj[u][i];
if( !dfn[v] ){
Tarjan( v );
up_min( low[u], low[v] );
}
else if( vis[v] )
up_min( low[u], dfn[v] );
}
if( low[u]==dfn[u] ){
++Bcnt;
int v;
do{
v= stack[Top--];
belong[v]= Bcnt;
vis[v]= 0; /// pop() from stack;
}while( u!=v );
}
}

int in[maxn], out[maxn];
void dfs(int u){;
vis[u]= 1;
for(int i=0;i<adj[u].size();++i){
int v= adj[u][i];
if( belong[u] !=belong[v] ){
out[ belong[u] ]++;
in[ belong[v] ]++;
}
if( !vis[v] )
dfs( v );
}
}

int main()
{
//freopen("1236.in","r",stdin);
int i,t;
while(cin>>n){
for(i=1;i<=n;++i) adj[i].clear();
for(i=1;i<=n;++i){
while( scanf("%d", &t), t )
adj[i].push_back( t );
}

Init_tarjan();
for(i=1;i<=n;++i)
if( !dfn[i] ){ /// dfn[i]!!!
Tarjan(i);
}

if( 1==Bcnt ){ ///
puts("1\n0");
continue;
}

for(i=1;i<=Bcnt;++i) in[i]= out[i]= 0;
fill( vis+1, vis+1+n, 0 );
for(i=1;i<=n;++i){
if( !vis[i] )
dfs(i);
}

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