标签:
题意:有多个命题,需要证明他们可以互相推出,现在已经有一些证明关系即 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 }
UVALive4287 hdu2767 hdu3836 强连通
标签:
原文地址:http://www.cnblogs.com/cenariusxz/p/4799152.html