第一道连通图题吧以此纪念下
题意:给一张有向无环图有两个任务
1.最至少要选几个顶点,才能做到从这些顶点出发,可以到达全部顶点
2.至少要加多少条边,才能使得从任何一个顶点出发,都能到达全部顶点
解题思路:
1. 求出所有强连通分量
2. 每个强连通分量缩成一点,则形成一个有向无环图DAG。
3. DAG上面有多少个入度为0的顶点,问题1的答案就是多少
4. 在DAG上要加几条边,才能使得DAG变成强连通的,问题2的答案就是多少
5. 怎么加边呢:两种 n :表示入度为0的个数,m:出度为0的个数 问题2的答案 为 max(n,m);
1.求强连通分量采用的是Targan算法
不懂的移步吧 https://www.byvoid.com/zhs/blog/scc-tarjan
/*===================================================
* Author : Uniontake
* Email : mr.uniontake@gmail.com
* File : A-poj1236-Network-of-Schools.cpp CPP
* Creat Date : 2017-10-06 11:09:16
* Do one thing at a time, and do well
===================================================*/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <iomanip>
#define mem(a,x) memset(a,x,sizeof(a))
#define gcd(a,b) __gcd(a,b)
#define lowbit(x) (x&-x)
#define LL long long
#define MOD 1000000007
#define INF 0x3f3f3f3f
#define pi (acos(-1.0))
#define eps (1e-8)
using namespace std;
const int maxn = 110;
int n; //num
int dfs_num;
int dfn[maxn]; //递归次序
int low[maxn]; //回溯堆栈中最早的节点
int sta[maxn];
bool vis[maxn]; //判断元素是否在堆栈中
int maze[maxn][maxn]; //邻接矩阵
int indegree[maxn],outdegree[maxn]; //出度入度
int color[maxn];
int colorsnum;
int top;
void Targan(int u)
{
dfn[u] = low[u] = ++dfs_num;
sta[top++] = u;
vis[u] = true;
for(int i=1;i<=n;i++) if(maze[u][i])
{
if(!dfn[i])
{
Targan(i);
low[u] = min(low[u],low[i]);
}
else if(vis[i]) { low[u] = min(low[u],dfn[i]); }
}
if(dfn[u] == low[u])
{
colorsnum++;
while(1)
{
int v = sta[--top];
color[v] = colorsnum;
vis[v] = false;
if( v == u ) break;
}
}
}
void init()
{
top = 0;
colorsnum = 0;
dfs_num = 0;
mem(color,0);
mem(maze,0);
mem(dfn,0);
mem(sta,0);
mem(low,0);
mem(vis,false);
mem(indegree,0);
mem(outdegree,0);
}
int main()
{
while(~scanf("%d",&n))
{
init();
int x;
for(int i=1;i<=n;i++)
{
while(scanf("%d",&x))
{
if(!x) break;
maze[i][x] = 1;
}
}
for(int i=1;i<=n;i++) if(!dfn[i]) //图不是连通的
Targan(i);
if(colorsnum == 1) //特判
{
printf("1\n0\n");
continue;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++) if(maze[i][j] && color[i]!=color[j])
{
outdegree[color[i]]++;
indegree[color[j]]++;
}
}
int ans1,ans2;
ans1 = ans2 = 0;
for(int i=1;i<=colorsnum;i++)
{
if(!indegree[i]) ans1++;
if(!outdegree[i]) ans2++;
}
printf("%d\n%d\n",ans1,max(ans1,ans2));
}
return 0;
}