1. 程式人生 > >B - Network of Schools POJ - 1236(Tarjan求強連通分量+縮點)

B - Network of Schools POJ - 1236(Tarjan求強連通分量+縮點)

題目連結

題意:
給出你一個圖,代表許多學校的網路連線情況,第一個問題:要想把一個資訊傳輸到所有節點至少要在幾個節點上放置資訊。第二個問題:想要把整個圖變成強連通圖需要增加多少條邊。

思路:
對於第一個問題,找到所有的強連通分量,然後把其縮成一個點,然後再看整個圖,統計一下入度為0的點,就是答案(PS:注意整個圖是強連通圖,也就是入度為0的點不存在,這時應該輸出1)。
對於第二個問題,還是和每個節點的度有關係(縮點之後的),統計出度為0的點的數量和入度為0的點的數量,我們要保證取縮點之後不存在出度為0或入度為0的點,所以取二者最大值即為答案(我們可以在入度為0和出度為0的點之間建邊,多餘的點隨便拉一條邊接到其他節點上就行)。

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int maxn = 1020;

int n, tot, num, top, sum;
int head[maxn], Stack[maxn], dfn[maxn], color[maxn];
int low[maxn], degree_in[maxn], degree_out[maxn];

struct node
{
    int v, next;
}edge[maxn *
10]; inline void add(int u, int v) { edge[tot].v = v; edge[tot].next = head[u]; head[u] = tot++; } inline void Init() { top = 0; sum = 0; num = 0; tot = 0; memset(head, -1, sizeof(head)); memset(dfn, -1, sizeof(dfn)); memset(degree_in, 0, sizeof(degree_in)); memset
(degree_out, 0, sizeof(degree_out)); } void Tarjan(int u) { dfn[u] = low[u] = ++num; Stack[++top] = u; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].v; if(dfn[v] == -1) { //如果沒有被訪問過 Tarjan(v); low[u] = min(low[u], low[v]); } else if(color[v] == 0) {       //如果被訪問過,但是不是其他強連通分量的一部分 low[u] = min(low[u], dfn[v]); } } if(low[u] == dfn[u]) {        //找到一個強連通分量 color[u] = ++sum;         //重新編號,相當於縮點 while(Stack[top] != u) {     color[Stack[top--]] = sum; } top --; } } int main() { //freopen("in.txt", "r", stdin); cin >> n; Init(); for(int i = 1; i <= n; ++ i) { int v; while(1) { scanf("%d", &v); if(v == 0) break; add(i, v); } } for(int i = 1; i <= n; ++ i) { //不一定是連通圖 if(dfn[i] == -1) Tarjan(i); } for(int i = 1; i <= n; ++ i) { for(int j = head[i]; j != -1; j = edge[j].next) { int v = edge[j].v; if(color[v] != color[i]) { //不是一個強連通分量的話就連線,但是沒有實際操作,只是記錄一下出度和入度,有需要的話可以直接連線 degree_in[color[v]] ++; degree_out[color[i]] ++; } } } int in = 0, out = 0; for(int i = 1; i <= sum; ++ i) { if(degree_in[i] == 0) in++; if(degree_out[i] == 0) out++; } if(sum == 1)    //注意整個圖都是強連通圖的話要特判一下 printf("1\n0\n"); else printf("%d\n%d\n", in, max(in, out)); return 0; }