POJ 1236 Network of Schools ★(经典问题:强联通分量+缩点)
2013-05-21 21:13
393 查看
题意:N(2<N<100)个学校之间有单向的网络,每个学校得到一套软件后,可以通过单向网络向周边的学校传输,问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。2,至少需要添加几条传输线边,使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件。
分析:先求出图的强连通分量(我用的Korasaju,也可以用Tarjan),然后将所有的强连通分量缩成一个点(缩点),这样原来的有向图就缩成了一个DAG图(有向无环图)。问题1就是求入度为0的点的个数;问题2是问最少需要连接多少条边才可以使图为一个强连通图。因为两个强连通合并必然是出度为0的连接入度为0的点,所以要解决掉入度为0,和出度为0的点,所以答案是这两个的最大值(点指缩点)。
分析:先求出图的强连通分量(我用的Korasaju,也可以用Tarjan),然后将所有的强连通分量缩成一个点(缩点),这样原来的有向图就缩成了一个DAG图(有向无环图)。问题1就是求入度为0的点的个数;问题2是问最少需要连接多少条边才可以使图为一个强连通图。因为两个强连通合并必然是出度为0的连接入度为0的点,所以要解决掉入度为0,和出度为0的点,所以答案是这两个的最大值(点指缩点)。
#include #include #include #include #include #include #include #include #include #include #include #include #define MID(x,y) ((x+y)>>1) #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; const int MAXV = 105; const int MAXE = 20005; /* ----------- 强联通分量Kosaraju算法 ----------- */ struct node{ int u, v; int next; }arc[MAXE], t_arc[MAXE]; int cnt, head[MAXV], t_head[MAXV]; int d[MAXV], f[MAXV]; //深搜时间戳 int order[MAXV]; //结束时间戳为i的节点标号 int scc[MAXV], scc_num; //每个节点所属强连通分量编号,强连通分量总数 void init(){ cnt = 0; mem(head, -1); mem(t_head, -1); } void add(int u, int v){ arc[cnt].u = u; arc[cnt].v = v; arc[cnt].next = head[u]; head[u] = cnt; t_arc[cnt].u = v; t_arc[cnt].v = u; t_arc[cnt].next = t_head[v]; t_head[v] = cnt ++; return ; } bool vis[MAXV]; int id, fid; void dfs(int u){ vis[u] = 1; d[u] = id ++; for (int i = head[u]; i != -1; i = arc[i].next){ int v = arc[i].v; if (!vis[v]){ dfs(v); } } f[u] = id; order[fid ++] = u; return ; } void dfs_t(int u){ vis[u] = 1; scc[u] = scc_num; for (int i = t_head[u]; i != -1; i = t_arc[i].next){ int v = t_arc[i].v; if (!vis[v]){ dfs_t(v); } } return ; } void Kosaraju(int n){ //init scc_num = 0; mem(scc, -1); mem(d, -1); mem(f, -1); mem(order, -1); mem(vis, 0); id = fid = 0; for (int u = 1; u <= n; u ++){ //注意图中节点编号从几开始 if (!vis[u]){ dfs(u); } } mem(vis, 0); for (int i = n - 1; i >= 0; i --){ int u = order[i]; if (!vis[u]){ scc_num ++; dfs_t(u); } } } /* ----------- 强联通分量Kosaraju算法 ----------- */ int ans1, ans2; int indeg[MAXV], outdeg[MAXV]; //缩点的入度、出度,缩点编号为强连通分支的编号. void solve(int n){ mem(indeg, 0); mem(outdeg, 0); for (int u = 1; u <= n; u ++){ for (int i = head[u]; i != -1; i = arc[i].next){ int v = arc[i].v; if (scc[u] != scc[v]){ indeg[scc[v]] ++; //缩点入度 outdeg[scc[u]] ++; //缩点出度 } } } ans1 = 0; int ans21 = 0, ans22 = 0; for (int i = 1; i <= scc_num; i ++){ if (indeg[i] == 0){ ans1 ++; ans21 ++; } if (outdeg[i] == 0){ ans22 ++; } } ans2 = max(ans21, ans22); } int main(){ int n; scanf("%d", &n); init(); for (int i = 1; i <= n; i ++){ int j; while(scanf("%d", &j), j){ add(i, j); } } Kosaraju(n); solve(n); if (scc_num == 1) ans2 = 0; printf("%d\n%d\n", ans1, ans2); return 0; }
相关文章推荐
- POJ 1236 Network of Schools ★(经典问题:强联通分量+缩点)
- 【POJ 1236 Network of Schools】强联通分量问题 Tarjan算法,缩点
- 文章标题 POJ 1236 : Network of Schools (强联通分量+缩点)
- poj 1236 Network of Schools (强联通分量+缩点)
- Network of Schools POJ - 1236 tarjan强连通分量缩点
- POJ 1236 Network Of Schools ( tarjan求强连通分量 + 缩点成DAG图 )
- 【强连通分量缩点】poj 1236 Network of Schools
- POJ 1236 Network of Schools(强联通分量)
- poj-1236-Network of Schools-强联通分量
- POJ 1236 Network of Schools 强联通分量求出度为0的点和入度为0的点的数目
- 强连通分量,Tarjan,缩点(Network of Schools,POJ 1236)
- POJ 1236 Network of Schools(强联通缩点)
- POJ 1236 Network of Schools (tarjan求强连通,缩点)
- POJ 1236 Network of Schools(Tarjan + 缩点 + 计算出度and入度)
- POJ 1236 Network of Schools[连通分量]
- poj 1236 Network of Schools 1 (tarjan 缩点)
- [ACM] poj 1236 Network of Schools (有向强连通分量)
- poj 1236 Network of Schools (强连通分支缩点)
- POJ 1236 Network of Schools(强连通分量,缩点)
- POJ 1236 Network of Schools(Targan缩点)