POJ 1236 SCC+缩点

题意:一张有向图,一问至少给几个点发送软件,才能让所有点都能收到软件;二问是至少添加几条边才能让整个图是一个连通分量;

分析:一般求连通分量都会求缩点,在这里缩点之后,生成一张新的图,在新的图中求每一个点的出度,入度。答案就是sum(入度=0),max(sum(出度 == 0),sum(入度 == 0));

注意:如果整张图本来就是一个强连通分量,需要特判。因为它出度,入度都等于0,即max(1,1) = 1,但是实际上不用再补充边了,应该是0,按照上面的分析答案就错了。

  1 ///POJ1236
  2 ///时间复杂度也是O(N+M)
  3 #include <stdio.h>
  4 #include <string.h>
  5 #include <vector>
  6 #include <stack>
  7 #include <iostream>
  8 #define repu(i,a,b) for(int i=a;i<b;i++)
  9 using namespace std;
 10 #define N 105            /// 题目中可能的最大点数
 11 stack<int>sta;            /// 存储已遍历的结点
 12 vector<int>gra[N];        /// 邻接表表示图
 13 int dfn[N];        /// 深度优先搜索访问次序
 14 int low[N];        /// 能追溯到的最早的次序
 15 int InStack[N];
 16 /// 检查是否在栈中(2:在栈中,1:已访问,且不在栈中,0:不在)
 17 vector<int> Component[N]; /// 获得强连通分量结果
 18 int InComponent[N];          /// 记录每个点在第几号强连通分量里
 19 int Index,ComponentNumber;/// 索引号,强连通分量个数
 20 int n, m;          /// 点数,边数
 21 int d[N][N],chu[N],ru[N];
 22
 23 void init()///清空容器,数组
 24 {
 25     memset(dfn, 0, sizeof(dfn));
 26     memset(low, 0, sizeof(low));
 27     memset(chu, 0, sizeof(chu));
 28     memset(ru, 0, sizeof(ru));
 29     memset(InStack, 0, sizeof(InStack));
 30     Index = ComponentNumber = 0;
 31     for (int i = 1; i <= n; ++ i)
 32     {
 33         gra[i].clear();
 34         Component[i].clear();
 35     }
 36     repu(i,1,n+1)
 37     repu(j,1,n+1)
 38     d[i][j] = 0;
 39     while(!sta.empty())
 40         sta.pop();
 41 }
 42 void tarjan(int u)
 43 {
 44     InStack[u] = 2;
 45     low[u] = dfn[u] = ++ Index;
 46     sta.push(u);///寻找u所在的强连通分量
 47     for (int i = 0; i < gra[u].size(); ++ i)
 48     {
 49         int t = gra[u][i];
 50         if (dfn[t] == 0)///不在的继续递归
 51         {
 52             tarjan(t);///递归到头了就
 53             low[u] = min(low[u], low[t]);
 54         }
 55         else if (InStack[t] == 2)///在栈里
 56         {
 57             low[u] = min(low[u], dfn[t]);
 58         }
 59     }
 60     if(low[u] == dfn[u])///sta出栈就是一个强连通分量的
 61     {
 62         ++ComponentNumber;///强连通分量个数
 63         while (!sta.empty())
 64         {
 65             int j = sta.top();
 66             sta.pop();
 67             InStack[j] = 1;///已访问但不在栈中
 68             Component[ComponentNumber].push_back(j);
 69             ///用vector存储第ComponentNumber个强连通分量
 70             InComponent[j]=ComponentNumber;
 71             ///记录每个点在第几号强连通分量里
 72             if (j == u)
 73                 break;
 74         }
 75     }
 76 }
 77 void input()
 78 {
 79     repu(i,1,n+1)
 80     {
 81         while(scanf("%d",&m) &&m)
 82             d[i][m] = 1,gra[i].push_back(m);///有向图才有强连通分量
 83     }
 84 }
 85
 86 void solve(void)
 87 {
 88     for(int i=1; i<=n; i++)
 89         if(!dfn[i])
 90             tarjan(i);
 91     if(ComponentNumber == 1)
 92     {
 93         printf("1\n0\n");
 94         return;
 95     }
 96     ///缩点
 97     for(int i=1; i<=ComponentNumber; i++)
 98     {
 99         for(int j = 0; j < Component[i].size(); j++)
100         {
101             for(int k = 1; k<=n; k++)
102             {
103                 if(d[k][Component[i][j]] && k != Component[i][j])
104                 {
105                     int s = InComponent[k];
106                     int t = InComponent[Component[i][j]];
107                     if(s!=t)
108                     {
109                         chu[s]++;
110                         ru[t]++;
111                     }
112                 }
113             }
114         }
115     }
116     int sum = 0,num = 0;
117     for(int i=1; i<=ComponentNumber; i++)
118     {
119         if(!chu[i])
120             sum++;
121         if(!ru[i])
122             num++;
123     }
124     printf("%d\n%d\n",num,max(sum,num));
125 }
126
127 int main()
128 {
129     while(~scanf("%d",&n))
130     {
131         init();
132         input();
133         solve();
134         /*每一个强连通分量的具体数字
135         for(int i = 1; i <= ComponentNumber; i++)
136         {
137             for(int j = 0; j < Component[i].size(); j++)
138                 if(!j)
139                     cout << Component[i][j];
140                 else
141                     cout <<"-->"<< Component[i][j];
142             cout<<endl;
143         }
144         */
145     }
146     return 0;
147 }

时间: 2024-08-24 04:53:09

POJ 1236 SCC+缩点的相关文章

poj 1236 scc强连通分量

分析部分摘自:http://www.cnblogs.com/kuangbin/archive/2011/08/07/2130277.html 强连通分量缩点求入度为0的个数和出度为0的分量个数 题目大意:N(2<N<100)各学校之间有单向的网络,每个学校得到一套软件后,可以通过单向网络向周边的学校传输,问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件.2,至少需要添加几条传输线路(边),使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件

POJ 1236 tarjan缩点+度数

Network of Schools Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 11441   Accepted: 4554 Description A number of schools are connected to a computer network. Agreements have been developed among those schools: each school maintains a li

NYOJ-120 校园网络 &amp;&amp;POJ 1236 (强连通缩点targan算法)

链接:click here 题意: 校园网络 时间限制:3000 ms  |  内存限制:65535 KB 难度:5 描述 南阳理工学院共有M个系,分别编号1~M,其中各个系之间达成有一定的协议,如果某系有新软件可用时,该系将允许一些其它的系复制并使用该软件.但该允许关系是单向的,即:A系允许B系使用A的软件时,B未必一定允许A使用B的软件. 现在,请你写一个程序,根据各个系之间达成的协议情况,计算出最少需要添加多少个两系之间的这种允许关系,才能使任何一个系有软件使用的时候,其它所有系也都有软件

POJ 1236 Network of Schools(强连通 Tarjan+缩点)

POJ 1236 Network of Schools(强连通 Tarjan+缩点) ACM 题目地址:POJ 1236 题意: 给定一张有向图,问最少选择几个点能遍历全图,以及最少加入?几条边使得有向图成为一个强连通图. 分析: 跟HDU 2767 Proving Equivalences(题解)一样的题目,只是多了个问题,事实上转化成DAG后就不难考虑了,事实上仅仅要选择入度为0的点即可了. 代码: /* * Author: illuz <iilluzen[at]gmail.com> *

POJ 1236 Network of Schools - 缩点

POJ 1236 :http://poj.org/problem?id=1236 参考:https://www.cnblogs.com/TnT2333333/p/6875680.html 题意: 有好多学校,每个学校可以给其他特定的学校发送文件.第一个问题是最少要给几个学校发文件,可以使得全部的学校收到文件.第二个问题是最少要加几条线路,使得随意挑一个学校发文件,也能使得全部的学校收到文件. 思路: 第一个问题,可以用tarjan给图中先缩点,因为强连通的环相互可达.所以只要数出缩完点后图中入度

POJ 1236

Network of Schools Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 10500   Accepted: 4189 Description A number of schools are connected to a computer network. Agreements have been developed among those schools: each school maintains a li

poj 1236 Network of Schools 【强连通图】

题目:poj 1236 Network of Schools 类似题目hdoj 2767 3836 /*******以下kuang大神的解释,写的很好就不解释了*************************/ 强连通分量缩点求入度为0的个数和出度为0的分量个数 题目大意:N(2<N<100)各学校之间有单向的网络,每个学校得到一套软件后,可以通过单向网络向周边的学校传输,问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件.2,至少需要添加几条传输线路(边),使任

POJ 1236 学校网络间的强连通

题目大意: N个学校之间有单向的网络,每个学校得到一套软件后,可以通过单向网络向周边的学校传输.问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件.问题2:至少需要添加几条传输线路(边),使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件. 链接http://vjudge.net/problem/viewProblem.action?id=17001 每个强连通分量内只要有任意一个学校获得一份软件就可以了,因为强连通分量内的任意两点是相互可达

POJ 1236——Network of Schools——————【加边形成强连通图】

Network of Schools Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 1236 Description A number of schools are connected to a computer network. Agreements have been developed among those schools: e