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

题意:有n个命题,已知其中的m个推导,要证明n个命题全部等价(等价具有传递性),最少还需要做出几次推导。

思路:由已知的推导可以建一张无向图,则问题变成了最少需要增加几条边能使图变成强连通图。找出所有的强连通分量,将每一个连通分量视作一个大节点,则整张图变成了一张DAG。设出度为0的大节点个数为b,入度为0的大节点个数为a,则答案就是max(a,b)。

  1 #include<iostream>
  2 #include<string>
  3 #include<algorithm>
  4 #include<cstdlib>
  5 #include<cstdio>
  6 #include<set>
  7 #include<map>
  8 #include<vector>
  9 #include<cstring>
 10 #include<stack>
 11 #include<cmath>
 12 #include<queue>
 13 #define clc(a,b) memset(a,b,sizeof(a))
 14 #include <bits/stdc++.h>
 15 using namespace std;
 16 #define LL long long
 17 const int maxn = 20005;
 18 const int inf=0x3f3f3f3f;
 19 const double pi=acos(-1);
 20 int  in[maxn],out[maxn];
 21 vector<int>G[maxn];
 22 int pre[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt;
 23 stack<int>S;
 24
 25 void dfs(int u)
 26 {
 27     pre[u]=lowlink[u]=++dfs_clock;
 28     S.push(u);
 29     for(int i=0; i<G[u].size(); i++)
 30     {
 31         int v=G[u][i];
 32         if(!pre[v])
 33         {
 34             dfs(v);
 35             lowlink[u]=min(lowlink[u],lowlink[v]);
 36         }
 37         else if(!sccno[v])
 38         {
 39             lowlink[u]=min(lowlink[u],pre[v]);
 40         }
 41     }
 42     if(lowlink[u]==pre[u])
 43     {
 44         scc_cnt++;
 45         for(;;)
 46         {
 47             int x=S.top();
 48             S.pop();
 49             sccno[x]=scc_cnt;
 50             if(x==u)
 51                 break;
 52         }
 53     }
 54 }
 55
 56 void find_scc(int n)
 57 {
 58     dfs_clock=scc_cnt=0;
 59     clc(sccno,0);
 60     clc(pre,0);
 61     for(int i=0; i<n; i++)
 62         if(!pre[i])
 63             dfs(i);
 64 }
 65
 66 int main()
 67 {
 68     int t,n,m;
 69     scanf("%d",&t);
 70     while(t--)
 71     {
 72         scanf("%d%d",&n,&m);
 73         for(int i=0; i<n; i++)
 74             G[i].clear();
 75         for(int i=0; i<m; i++)
 76         {
 77             int u,v;
 78             scanf("%d%d",&u,&v);
 79             u--;
 80             v--;
 81             G[u].push_back(v);
 82         }
 83         find_scc(n);
 84         for(int i=1; i<=scc_cnt; i++)
 85             in[i]=out[i]=0;
 86         for(int u=0; u<n; u++)
 87         {
 88             for(int i=0; i<G[u].size(); i++)
 89             {
 90                 int v=G[u][i];
 91                 if(sccno[u]!=sccno[v])
 92                     in[sccno[v]]=out[sccno[u]]=1;
 93             }
 94         }
 95         int a=0,b=0;
 96         for(int i=1; i<=scc_cnt; i++)
 97         {
 98             if(!in[i])
 99                 a++;
100             if(!out[i])
101                 b++;
102         }
103         int ans=max(a,b);
104         if(scc_cnt==1)
105             ans=0;
106         printf("%d\n",ans);
107     }
108     return 0;
109 }

时间: 2024-12-24 08:27:34

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

hdu2767 Proving Equivalences有向图的强连通_Tarjan缩点

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 4343    Accepted Submission(s): 1541 Problem Description Consider the following exercise, found in a generic linear algebra textbook. Let A be an

UVALive 4287 SCC-Tarjan 加边变成强连通分量

还是强连通分量的题目,但是这个题目不同的在于,问你最少要添加多少条有向边,使得整个图变成一个强连通分量 然后结论是,找到那些入度为0的点的数目 和 出度为0的点的数目,取其最大值即可,怎么证明嘛...我也不好怎么证,不过细细一琢磨发现就是这样,改天找聪哥一起探讨下怎么证明 #include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <stack&

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个命题等价 解题思路:命题的等价,就相当于证明点到点之间是互相连通. 所以,将所给的命题证明当成一条有向边,构建出一

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

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

LA 4287 等价性证明(强连通分量缩点)

https://vjudge.net/problem/UVALive-4287 题意: 给出n个结点m条边的有向图,要求加尽量少的边,使得新图强连通. 思路:强连通分量缩点,然后统计缩点后的图的每个结点是否还需要出度和入度. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<sstream> 6 #include

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

链接 : http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=10294 题意 :  告诉你n个等价的命题 和m个关系 比如 (u,v)代表u可以推导出v, 问至少需要补充多少条边. 用强连通缩点成一张DAG. #include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <

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

有向图的强连通分量(tarjan算法)

强连通分量 有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.有向图的极大强连通子图,称为强连通分量(strongly connected components). 考虑强连通分量C,设其中第一个被发现的点为x,则,C中其他的点都是x的后代.我们希望在x访问完成时立即输出C(可以同时记录C,输出代表

hdu1269 迷宫城堡,有向图的强连通分量 , Tarjan算法

hdu1269 迷宫城堡 验证给出的有向图是不是强连通图... Tarjan算法板子题 Tarjan算法的基础是DFS,对于每个节点.每条边都搜索一次,时间复杂度为O(V+E). 算法步骤: 1.搜索到某一个点时,将该点的Low值标上时间戳,然后将自己作为所在强连通分量的根节点(就是赋值Dfn=Low=time) 2.将该点压入栈. 3.当点p有与点p'相连时,如果此时p'不在栈中,p的low值为两点的low值中较小的一个. 4.当点p有与点p'相连时,如果此时p'在栈中,p的low值为p的lo