|Vijos|IOI1996|图论强连通分量|P1595 学校网络

来源:互联网 发布:windows 95 编辑:程序博客网 时间:2024/04/29 08:39

https://vijos.org/p/1595

tarjan求强连通分量后缩点,计算出度和入度,入度为0的点的个数为第一问答案,第二问答案为max(入度为0的点的个数, 出度为0的点的个数)

#include<cstdio>#include<cstring>#include<algorithm>#include<stack>#include<vector>#include<cmath>#define ms(i,j) memset(i, j, sizeof(i));using namespace std;struct node{int x;int y;};//边 int n; vector<node> q[105];//邻接表 int c_num = 0;//强连通分量的个数 int c_cnt[105];//强连通分量的入度int c_dnt[105];//强连通分量的出度int c_de[105];//每个点属于的强连通分量 stack<int> s;//tarjan栈int index = 0;//tarjan索引int dn[105];//tarjan时间戳int low[105];//tarjan追溯到的最小标号 int ex[105];//tarjan访问数组 void tarjan(int u){dn[u]=low[u]=++index; ex[u] = -1; s.push(u);for (int i=0;i<q[u].size();i++){node p = q[u][i];int v = p.y;if (ex[v]==0){tarjan(v);low[u] = min(low[u], low[v]);} elseif (ex[v]==-1){low[u] = min(low[u], dn[v]);}}int e;if (dn[u]==low[u]){c_num++;do{e = s.top();s.pop();ex[e] = 1;c_de[e] = c_num;} while (e!=u);}}void dr (){ms(c_cnt,0);ms(c_dnt,0);for (int k=1;k<=n;k++){for (int i=0;i<q[k].size();i++){int j = q[k][i].y;if (c_de[k]!=c_de[j]){c_cnt[c_de[j]]++;c_dnt[c_de[k]]++;}}}}int k1,k2;void rzero(){k1 = 0;k2 = 0;for (int i=1;i<=c_num;i++){if (c_cnt[i]==0) k1++;if (c_dnt[i]==0) k2++;}}int main () { scanf("%d", &n);for (int i=1;i<=n;i++){int a;scanf("%d", &a);while (a!=0){node r;r.x = i, r.y = a;q[i].push_back(r);scanf("%d", &a);}}ms(dn, 0);ms(ex,0); for (int i=1;i<=n;i++)if (!dn[i]) tarjan(i); if (c_num==1) {printf("1\n0\n"); return 0;}dr();rzero();printf("%d\n%d\n", k1, max(k1,k2));return 0;}



0 0