http://poj.org/problem?id=1236
题意:给你一个有向图,1、求最少给多少的点发信息,可以使得所有的点都可以得到信息,2、求最少加上多少条边后,可以使图强连通。
题解:1、跑完tarjan算法后,将每个强连通分量缩点,然后求出入度为0的缩点的个数,这也是最小点基的定义。2、最少加上多少条边后,可以使图强连通。可以发现找出入度为0和出度为0的缩点个数a,b。若a>b,可以从每个入度为0的点向出度为0的点连边,反之亦然。这样保证了强连通。
另:需对本就是强连通的图特判,因为a=b=1。
代码:
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<string>
#include<bitset>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<iomanip>
#include<iostream>
#define debug cout<<"aaa"<<endl
#define d(a) cout<<a<<endl
#define mem(a,b) memset(a,b,sizeof(a))
#define LL long long
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define MIN_INT (-2147483647-1)
#define MAX_INT 2147483647
#define MAX_LL 9223372036854775807i64
#define MIN_LL (-9223372036854775807i64-1)
using namespace std;
const int N = 100 + 5;
const int mod = 1000000000 + 7;
const double eps = 1e-8;
int head[N],len;
int dfn[N],low[N],dfs_num;//dfn表示遍历深度,low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号
int color[N],col_num;//染色
int stack[N],vis[N],top;//栈和栈指针
int outd[N],ind[N];
int ans1,ans2;
struct EdgeNode{
int from,to,next;
}edge[N*N];
void add(int i,int j){
edge[len].from=i;
edge[len].to=j;
edge[len].next=head[i];
head[i]=len++;
}
void init(int n){
mem(outd,0),mem(ind,0),mem(vis,0),mem(dfn,0),mem(low,0),mem(head,-1),len=ans1=ans2=top=col_num=dfs_num=0;
}
void tarjan(int x){
dfn[x]=++dfs_num;
low[x]=dfs_num;
vis[x]=1;//是否在栈中
stack[++top]=x;
for(int i=head[x];i!=-1;i=edge[i].next){
int temp=edge[i].to;
if(!dfn[temp]){
tarjan(temp);
low[x]=min(low[x],low[temp]);
}
else if(vis[temp]){
low[x]=min(dfn[temp],low[x]);
}
}
if(dfn[x]==low[x]){//构成强连通分量
vis[x]=0;
//染色
color[x]=++col_num;
while(stack[top]!=x){//退栈
color[stack[top]]=col_num;
vis[stack[top]]=0;
top--;
}
top--;
}
}
void solve(int n){
for(int i=1;i<=n;i++){
if(!dfn[i]){
tarjan(i);
}
}
//计算入度并缩点
for(int i=0;i<len;i++){
if(color[edge[i].from]!=color[edge[i].to]){
ind[color[edge[i].to]]++;
outd[color[edge[i].from]]++;
}
}
for(int i=1;i<=col_num;i++){
//若入度为0,则加入最小权值
if(ind[i]==0){
ans1++;
}
if(outd[i]==0){
ans2++;
}
}
}
int main(){
int n,m,u,v;
while(~scanf("%d",&n)){
init(n);
for(int i=1;i<=n;i++){
while(scanf("%d",&v)&&v){
add(i,v);
}
}
solve(n);
if(col_num==1){
puts("1");
puts("0");
continue;
}
printf("%d\n",ans1);
printf("%d\n",max(ans1,ans2));
}
return 0;
}