UVALive4287 hdu2767 hdu3836 强连通

题意:有多个命题,需要证明他们可以互相推出,现在已经有一些证明关系即 A 可以证明 B,问至少还需要多少证明关系。

首先,如果某几个命题证明关系可以成环,那么这些命题必然可以相互证明,只要沿着环的边走就能到达其他命题,所以首先是需要强连通缩点,之后对于一个无环图,我们发现如果一个强连通分量它无出度,那么它就不能证明其他任何命题,如果它无入度,那么它就不能由任何命题证明,那么我们就需要消除这些入度或出度为0的点,其实只需要将入度为 0 的点建边指向出度为 0 的点,然后剩下多余的,入度为 0 则随意向其他点出边,出度为 0 则随意让其他点向它建边,因此所需要建的边数就是入度为 0 点数和出度为 0 点数的最大值。如果一开始图就只剩一个强连通分量,那么虽然它的入度出度都为 0 ,但已经不需要加边。

UVALive4287、hdu2767

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<stack>
 4 #include<queue>
 5 using namespace std;
 6
 7 const int maxn=2e4+5;
 8 const int maxm=5e4+5;
 9
10 int head[maxn],point[maxm],nxt[maxm],size;
11 int n,t,scccnt;
12 int stx[maxn],low[maxn],scc[maxn],id[maxn],od[maxn],numi,numo;
13 stack<int>S;
14
15 int min(int a,int b){return a<b?a:b;}
16 int max(int a,int b){return a>b?a:b;}
17
18 void init(){
19     memset(head,-1,sizeof(head));
20     size=0;
21 }
22
23 void add(int a,int b){
24     point[size]=b;
25     nxt[size]=head[a];
26     head[a]=size++;
27 }
28
29 void dfs(int s){
30     stx[s]=low[s]=++t;
31     S.push(s);
32     for(int i=head[s];~i;i=nxt[i]){
33         int j=point[i];
34         if(!stx[j]){
35             dfs(j);
36             low[s]=min(low[s],low[j]);
37         }
38         else if(!scc[j]){
39             low[s]=min(low[s],stx[j]);
40         }
41     }
42     if(low[s]==stx[s]){
43         scccnt++;
44         while(1){
45             int u=S.top();
46             S.pop();
47             scc[u]=scccnt;
48             if(s==u)break;
49         }
50     }
51 }
52
53 void setscc(){
54     memset(stx,0,sizeof(stx));
55     memset(scc,0,sizeof(scc));
56     memset(id,0,sizeof(id));
57     memset(od,0,sizeof(od));
58     numi=numo=t=scccnt=0;
59     for(int i=1;i<=n;++i)if(!stx[i])dfs(i);
60     if(scccnt!=1){
61         for(int i=1;i<=n;++i){
62             for(int j=head[i];~j;j=nxt[j]){
63                 int k=point[j];
64                 if(scc[i]!=scc[k]){
65                     id[scc[i]]++;
66                     od[scc[k]]++;
67                     if(id[scc[i]]==1)numi++;
68                     if(od[scc[k]]==1)numo++;
69                 }
70             }
71         }
72         numi=scccnt-numi;
73         numo=scccnt-numo;
74     }
75 }
76
77 int main(){
78     int T;
79     scanf("%d",&T);
80     while(T--){
81         int m;
82         scanf("%d%d",&n,&m);
83         init();
84         while(m--){
85             int a,b;
86             scanf("%d%d",&a,&b);
87             add(a,b);
88         }
89         setscc();
90         printf("%d\n",max(numi,numo));
91     }
92     return 0;
93 }
94         

hdu3836

恩,就是改下输入

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<stack>
 4 #include<queue>
 5 using namespace std;
 6
 7 const int maxn=2e4+5;
 8 const int maxm=5e4+5;
 9
10 int head[maxn],point[maxm],nxt[maxm],size;
11 int n,t,scccnt;
12 int stx[maxn],low[maxn],scc[maxn],id[maxn],od[maxn],numi,numo;
13 stack<int>S;
14
15 int min(int a,int b){return a<b?a:b;}
16 int max(int a,int b){return a>b?a:b;}
17
18 void init(){
19     memset(head,-1,sizeof(head));
20     size=0;
21 }
22
23 void add(int a,int b){
24     point[size]=b;
25     nxt[size]=head[a];
26     head[a]=size++;
27 }
28
29 void dfs(int s){
30     stx[s]=low[s]=++t;
31     S.push(s);
32     for(int i=head[s];~i;i=nxt[i]){
33         int j=point[i];
34         if(!stx[j]){
35             dfs(j);
36             low[s]=min(low[s],low[j]);
37         }
38         else if(!scc[j]){
39             low[s]=min(low[s],stx[j]);
40         }
41     }
42     if(low[s]==stx[s]){
43         scccnt++;
44         while(1){
45             int u=S.top();
46             S.pop();
47             scc[u]=scccnt;
48             if(s==u)break;
49         }
50     }
51 }
52
53 void setscc(){
54     memset(stx,0,sizeof(stx));
55     memset(scc,0,sizeof(scc));
56     memset(id,0,sizeof(id));
57     memset(od,0,sizeof(od));
58     numi=numo=t=scccnt=0;
59     for(int i=1;i<=n;++i)if(!stx[i])dfs(i);
60     if(scccnt!=1){
61         for(int i=1;i<=n;++i){
62             for(int j=head[i];~j;j=nxt[j]){
63                 int k=point[j];
64                 if(scc[i]!=scc[k]){
65                     id[scc[i]]++;
66                     od[scc[k]]++;
67                     if(id[scc[i]]==1)numi++;
68                     if(od[scc[k]]==1)numo++;
69                 }
70             }
71         }
72         numi=scccnt-numi;
73         numo=scccnt-numo;
74     }
75 }
76
77 int main(){
78     int m;
79     while(scanf("%d%d",&n,&m)!=EOF){
80         init();
81         while(m--){
82             int a,b;
83             scanf("%d%d",&a,&b);
84             add(a,b);
85         }
86         setscc();
87         printf("%d\n",max(numi,numo));
88     }
89     return 0;
90 }

时间: 2024-08-01 22:30:14

UVALive4287 hdu2767 hdu3836 强连通的相关文章

hdu2767 Proving Equivalences --- 强连通

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

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

UvaLive4287 roving Equivalences(Tarjan缩点+DAG)

UvaLive4287 roving Equivalences 题意:给n个定理,以及m个关系,即u定理可以推出v定理.问至少还需要加多少个条件,才能是定理两两互推. 思路:Tarjan缩点.然后变成一个DAG.ans1记录入度为0的联通块,ans2记录出度为0的联通块.输出较大值即可.注意如果点数为1或者只有一个强连通分量要输出0. /* ID: onlyazh1 LANG: C++ TASK: Knights of the Round Table */ #include<iostream>

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

UVa LA 4287 强连通 (类似 hdu 3836)

题目:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=25&problem=2288&mosmsg=Submission+received+with+ID+1488188 本题可在大白书的322页找到. 题意:给你一些有向边,问你至少需要加多少条边使之整个图强连通. 思路:先强连通缩点,缩点之后的图就不连通了

Kosaraju算法解析: 求解图的强连通分量

1. 定义 连通分量:在无向图中,即为连通子图. 上图中,总共有四个连通分量.顶点A.B.C.D构成了一个连通分量,顶点E构成了一个连通分量,顶点F,G和H,I分别构成了两个连通分量. 强连通分量:有向图中,尽可能多的若干顶点组成的子图中,这些顶点都是相互可到达的,则这些顶点成为一个强连通分量. 上图中有三个强连通分量,分别是a.b.e以及f.g和c.d.h. 2. 连通分量的求解方法 对于一个无向图的连通分量,从连通分量的任意一个顶点开始,进行一次DFS,一定能遍历这个连通分量的所有顶点.所以

POJ 2186 Popular Cows 强连通分量模板

题意 强连通分量,找独立的块 强连通分量裸题 #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <algorithm> #include <iostream> using namespace std; const int maxn = 50005; int n, m; struct Edge { int v, next;

USACO network of school 强连通分量

这个题的意思是有一个有向图, 每个顶点可以发送软件到与其相连的顶点上, 现在问1,至少发送给几个顶点能满足所有顶点都收到软件, 2:如果想让这个图变成强连通图,至少添几条边.  特例是给定的图是一个强连通图的话答案是1, 0. 一般情况下我们先将这个图的强连通分量求出来缩成一个点然后统计入度为0的点和出度为0的点的个数, 答案一就是入度为0的点的个数, 答案就是他们两个之间的最大值.代码如下: /* ID: m1500293 LANG: C++ PROG: schlnet */ #include