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<vector>
  7 #include<stack>
  8 #include<queue>
  9 #include<cmath>
 10 #include<map>
 11 #include<set>
 12 using namespace std;
 13 typedef long long ll;
 14 typedef pair<int,ll> pll;
 15 const int INF = 0x3f3f3f3f;
 16 const int maxn=20000+5;
 17
 18 int n, m;
 19 int tot;
 20 int dfs_clock;
 21 int scc_cnt;
 22 int in[maxn];
 23 int out[maxn];
 24 int pre[maxn];
 25 int head[maxn];
 26 int sccno[maxn];
 27 int lowlink[maxn];
 28
 29 stack<int> S;
 30
 31 struct node
 32 {
 33     int v;
 34     int next;
 35 }e[50000+5];
 36
 37 void addEdge(int u, int v)
 38 {
 39     e[tot].v=v;
 40     e[tot].next=head[u];
 41     head[u]=tot++;
 42 }
 43
 44 void dfs(int u)
 45 {
 46     pre[u]=lowlink[u]=++dfs_clock;
 47     S.push(u);
 48     for(int i=head[u];i!=-1;i=e[i].next)
 49     {
 50         int v=e[i].v;
 51         if(!pre[v])
 52         {
 53             dfs(v);
 54             lowlink[u]=min(lowlink[u],lowlink[v]);
 55         }
 56         else if(!sccno[v])
 57         {
 58             lowlink[u]=min(lowlink[u],pre[v]);
 59         }
 60     }
 61
 62     if(lowlink[u]==pre[u])
 63     {
 64         scc_cnt++;
 65         for(;;)
 66         {
 67             int x=S.top();S.pop();
 68             sccno[x]=scc_cnt;
 69             if(x==u)  break;
 70         }
 71     }
 72 }
 73
 74
 75 void find_scc()
 76 {
 77     dfs_clock=scc_cnt=0;
 78     memset(sccno,0,sizeof(sccno));
 79     memset(pre,0,sizeof(pre));
 80     for(int i=1;i<=n;i++)
 81     {
 82         if(!pre[i])  dfs(i);
 83     }
 84 }
 85
 86 int main()
 87 {
 88     //freopen("in.txt","r",stdin);
 89     int T;
 90     scanf("%d",&T);
 91     while(T--)
 92     {
 93         scanf("%d%d",&n,&m);
 94         tot=0;
 95         memset(head,-1,sizeof(head));
 96         while(m--)
 97         {
 98             int u,v;
 99             scanf("%d%d",&u,&v);
100             addEdge(u,v);
101         }
102         find_scc();
103         for(int i=1;i<=scc_cnt;i++)   in[i]=out[i]=1;
104         for(int u=1;u<=n;u++)
105         {
106             for(int i=head[u];i!=-1;i=e[i].next)
107             {
108                 int v=e[i].v;
109                 if(sccno[u]!=sccno[v])  in[sccno[v]]=out[sccno[u]]=0;  //u,v是桥,所以v不需要入度,u不需要出度
110             }
111         }
112
113
114         int a=0,b=0;
115         for(int i=1;i<=scc_cnt;i++)
116         {
117             if(in[i])  a++;
118             if(out[i]) b++;
119         }
120         int ans=max(a,b);
121         if(scc_cnt==1)  ans=0;
122         printf("%d\n",ans);
123     }
124     return 0;
125 }
时间: 2024-10-01 07:55:23

LA 4287 等价性证明(强连通分量缩点)的相关文章

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

ZOJ3795 Grouping(强连通分量+缩点+记忆化搜索)

题目给一张有向图,要把点分组,问最少要几个组使得同组内的任意两点不连通. 首先考虑找出强连通分量缩点后形成DAG,强连通分量内的点肯定各自一组,两个强连通分量的拓扑序能确定的也得各自一组. 能在同一组的就是两个强连通分量在不同的从入度0到出度0的强连通分量的路径上. 那么算法很直观就能想到了,用记忆化搜索,d[u]表示从强连通分量u出发到出度为0的强连通分量最少要几个组(最多有几个点). 1 #include<cstdio> 2 #include<cstring> 3 #inclu

【连通图|强连通分量+缩点】POJ-1236 Network of Schools

Network of Schools Time Limit: 1000MS Memory Limit: 10000K Description A number of schools are connected to a computer network. Agreements have been developed among those schools: each school maintains a list of schools to which it distributes softwa

UVA 11324 The Largest Clique (强连通分量缩点,图DP)

题目: http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=25&page=show_problem&problem=2299 题意: 给你一个有向图,求一个点集合的最大大小,使得此点集合中对于任意点对(u,v),有从u到v或者从v到u的边 方法: 先找强连通分量缩点,每个强连通分量显然满足条件,然后在缩点后的图中找到一条权值最大的路径,权值为此路径的点权之和,点权为这个

【差分约束系统】【强连通分量缩点】【拓扑排序】【DAG最短路】CDOJ1638 红藕香残玉簟秋,轻解罗裳,独上兰舟。

题意: 给定n个点(点权未知)和m条信息:u的权值>=v的权值+w 求点权的极小解和极大解(无解则输出-1) 极小解即每个点的点权可能的最小值 极大解即每个点的点权可能的最大值 题解: 差分约束系统 对于val[u]>=val[v]+w 要得到极小解,v是没有受限制的,其最小值为0 而u受到v的限制,显然,val[u]的最小值就是val[v]+w 在多条件限制下,我们用v连向u边权为w的边表示每个限制条件val[u]>=val[v]+w 那么如果得到的是拓扑图,则按拓扑序求到每个点的最长

【强连通分量缩点】【拓扑排序】【dp预处理】CDOJ1640 花自飘零水自流,一种相思,两处闲愁。

题意: 在n个点m条边的有向图上,从1出发的回路最多经过多少个不同的点 可以在一条边上逆行一次 题解: 在同一个强连通分量中,显然可以经过当中的每一个点 因此先将强连通分量缩点,点权为强连通分量的点数 如果不逆行,那么答案就是1所在的强连通分量的点数 如果逆行了,那么逆行的边必然在缩点后的拓扑图上 假设逆行的边为u->v,那么该回路可分为1到v和u到1两部分 经过的最多点数即1到v与u到1路径上的最大点权和减去1的点权 (这里的点指的都是缩点后的点) 例子中在边4->3上逆行就能从1出发经过所

POJ1236Network of Schools(强连通分量 + 缩点)

题目链接Network of Schools 参考斌神博客 强连通分量缩点求入度为0的个数和出度为0的分量个数 题目大意:N(2<N<100)各学校之间有单向的网络,每个学校得到一套软件后,可以通过单向网络向周边的学校传输,问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件.2,至少需要添加几条传输线路(边),使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件.   也就是: ?        给定一个有向图,求:   1) 至少要选几个顶

POJ2553 The Bottom of a Graph(强连通分量+缩点)

题目是问,一个有向图有多少个点v满足∀w∈V:(v→w)⇒(w→v). 把图的强连通分量缩点,那么答案显然就是所有出度为0的点. 用Tarjan找强连通分量: 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define MAXN 5555 6 #define MAXM 5555*5555 7 struct Edge{ 8 int u,v,nex