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 }
View Code

 

转载于:https://www.cnblogs.com/ACMERY/p/4681803.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值