UVALive Proving Equivalences (强连通分量,常规)

题意:给一个有向图,问添加几条边可以使其强连通。

思路:

  按照大白书p322做。tarjan算法求强连通分量,然后缩点求各个强连通分量的出入度,答案是max(入度为0的缩点个数,出度为0的缩点个数)。

 1 #include <bits/stdc++.h>
 2 #define LL long long
 3 #define pii pair<int,int>
 4 using namespace std;
 5 const int N=20000+5;
 6 const int INF=0x7f7f7f7f;
 7
 8 vector<int> vect[N];
 9 stack<int> stac;
10 bool chu[N], ru[N];
11 int scc_no[N], lowlink[N], dfn[N];
12 int dfn_clock, scc_cnt;
13 int n, m;
14
15 void DFS(int x)
16 {
17     stac.push(x);
18     dfn[x]=lowlink[x]=++dfn_clock;
19     for(int i=0; i<vect[x].size(); i++)
20     {
21         int t=vect[x][i];
22         if(!dfn[t])
23         {
24             DFS(t);
25             lowlink[x]=min(lowlink[x],lowlink[t]);
26         }
27         else if(!scc_no[t]) //如果t不属于任何一个强连通分量
28             lowlink[x]=min(lowlink[x],dfn[t]);
29     }
30     if(lowlink[x]==dfn[x])
31     {
32         scc_cnt++;
33         while(true)
34         {
35             int t=stac.top();
36             stac.pop();
37             scc_no[t]=scc_cnt;
38             if(t==x)    break;
39         }
40     }
41 }
42
43
44 int cal()
45 {
46     memset(dfn,0,sizeof(dfn));
47     memset(lowlink,0,sizeof(lowlink));
48     memset(scc_no,0,sizeof(scc_no));
49
50     dfn_clock=scc_cnt=0;
51     for(int i=1; i<=n; i++)    if(!dfn[i])    DFS(i);   //深搜
52     if(scc_cnt==1)  return -1;
53
54     memset(chu,0,sizeof(chu));
55     memset(ru,0,sizeof(ru));
56     for(int i=1; i<=n; i++)
57         for(int j=0; j<vect[i].size(); j++)  //统计出入度
58             if(scc_no[i]!=scc_no[vect[i][j]])    chu[scc_no[i]]=ru[scc_no[vect[i][j]]]=true;//这里麻烦了点,小心点出错
59
60     int c=0, r=0;
61     for(int i=1; i<=scc_cnt; i++)
62     {
63         if(!chu[i])    c++;
64         if(!ru[i])     r++;
65     }
66     return max(c,r)-1;
67 }
68
69
70 int main()
71 {
72     freopen("input.txt", "r", stdin);
73     int a, b, t;
74     cin>>t;
75     while(t--)
76     {
77         scanf("%d%d",&n,&m);
78         for(int i=1; i<=n; i++) vect[i].clear();
79         for(int i=0; i<m; i++)
80         {
81             scanf("%d%d", &a, &b);
82             vect[a].push_back(b);
83         }
84         printf("%d\n",cal());
85     }
86     return 0;
87 }

AC代码

时间: 2024-08-25 13:39:02

UVALive Proving Equivalences (强连通分量,常规)的相关文章

UVALive - 4287 Proving Equivalences(强连通分量 + DAG)

题目大意:给出N个命题,要求你证明这N个命题的等价性 比如有4个命题a,b,c,d,我们证明a<->b, b<->c,c<->d,每次证明都是双向的,因此一共用了6次推导 如果换成证明a->b,b->c,c->d,d->a,每次证明都是单向的,而只需4次就可以证明所有命题的等价性 现在给出M个命题证明,问还需要证明几个,才可以保证N个命题等价 解题思路:命题的等价,就相当于证明点到点之间是互相连通. 所以,将所给的命题证明当成一条有向边,构建出一

hdu2767 Proving Equivalences --- 强连通

给一个图,问至少加入?多少条有向边能够使图变成强连通的. 原图是有环的,缩点建图,在该DAG图上我们能够发现,要使该图变成强连通图必须连成环 而加入?最少的边连成环,就是把图上入度为0和出度为0的点连上,那么其它的点就都能够互相到达了 所以答案就是max(入度为0的点,出度为0的点) #include <iostream> #include <cstring> #include <string> #include <cstdio> #include <

hdu 2767 Proving Equivalences 强连通缩点

给出n个命题,m个推导,问最少增加多少条推导,可以使所有命题都能等价(两两都能互推) 既给出有向图,最少加多少边,使得原图变成强连通. 首先强连通缩点,对于新图,每个点都至少要有一条出去的边和一条进来的边(这样才能保证它能到任意点和任意点都能到它) 所以求出新图中入度为0的个数,和出度为0的个数,添加的边就是从出度为0的指向入度为0的.这样还会有一点剩余,剩余的就乱连就行了. 所以只要求出2者的最大值就OK. #include <iostream> #include<cstring>

hdu 2767 Proving Equivalences(强连通入门题)

1 /************************************************* 2 Proving Equivalences(hdu 2767) 3 强连通入门题 4 给个有向图,求至少加多少条边使得图是所有点都是强连通的 5 由a->b->c->a易知n个点至少要n条边,每个出度和入度都要大 6 于1.先求所有所有强连通分量,把每个强连通分量看成一个点 7 在找每个点的出度和入度,最后还差的出度和入度的最大值就是 8 答案. 9 10 ************

hdu - 2667 Proving Equivalences(强连通)

http://acm.hdu.edu.cn/showproblem.php?pid=2767 求至少添加多少条边才能变成强连通分量.统计入度为0的点和出度为0的点,取最大值即可. 1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <vector> 5 #include <cstring> 6 #include <algorithm> 7 #i

UvaLive 4287 Proving Equivalences 强连通缩点

原题链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2288 题意: 给你一个有向图,问你至少需要添加多少条边,使得整个图强连通. 题解: 就..直接缩点,令缩点后入度为0的点有a个,出度为0的点有b个,答案就是max(a,b) 代码: #include<iostream> #include<cstri

UVALIVE 4287 Proving Equivalences (强连通分量+缩点)

题意:给定一个图,问至少加入多少条边能够使这个图强连通. 思路:首先求出这个图的强连通分量.然后把每个强连通分量缩成一个点.那么这个图变成了一个DAG,求出全部点的入度和出度,由于强连通图中每个节点的入度和出度至少为1.那么我们求出入度为零的节点数量和出度为零的节点数量.答案取最大值,由于在一个DAG中加入这么多边一定能够使这个图强连通.注意当这个图本身强连通时要特判一下,答案为零. #include<cstdio> #include<cstring> #include<cm

UVA 12167 - Proving Equivalences(强连通分量+缩点)

UVA 12167 - Proving Equivalences 题目链接 题意:给定一些已经存在的等价性证明,要求全部等价,需要在多最少几次证明 思路:先求出强连通分量,然后进行缩点,在缩点后的图上统计入度和出度为0结点的最大值,就是需要加的边数,注意如果整个图已经是强连通,就直接是答案 代码: #include <cstdio> #include <cstring> #include <vector> #include <stack> #include

UVALive-4287 Proving Equivalences 有向图的强连通分量+缩点

题意:有n个命题,已知其中的m个推导,要证明n个命题全部等价(等价具有传递性),最少还需要做出几次推导. 思路:由已知的推导可以建一张无向图,则问题变成了最少需要增加几条边能使图变成强连通图.找出所有的强连通分量,将每一个连通分量视作一个大节点,则整张图变成了一张DAG.设出度为0的大节点个数为b,入度为0的大节点个数为a,则答案就是max(a,b). 1 #include<iostream> 2 #include<string> 3 #include<algorithm&g