题意:
给出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个命题等价。
分析:
缩点后求DAG中入度为0和出度为0的联通块的较大值。
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #define Maxn 20010 5 #define Maxm 50010 6 7 int first[Maxn],dfn[Maxn],low[Maxn],sta[Maxn],scc[Maxn]; 8 bool ru[Maxn],chu[Maxn]; 9 int cnt,sl,cl; 10 11 struct node 12 { 13 int x,y,next; 14 }t[Maxm]; 15 16 int mymin(int x,int y) {return x<y?x:y;} 17 int mymax(int x,int y) {return x>y?x:y;} 18 19 void ffind(int x) 20 { 21 dfn[x]=low[x]=++cnt; 22 sta[++sl]=x; 23 for(int i=first[x];i;i=t[i].next) 24 { 25 int y=t[i].y; 26 if(dfn[y]==0) 27 { 28 ffind(y); 29 low[x]=mymin(low[x],low[y]); 30 } 31 else if(scc[y]==0) low[x]=mymin(low[x],dfn[y]); 32 } 33 if(low[x]==dfn[x]) 34 { 35 cl++; 36 while(1) 37 { 38 int z=sta[sl--]; 39 scc[z]=cl; 40 if(z==x) break; 41 } 42 } 43 } 44 45 int main() 46 { 47 int T; 48 scanf("%d",&T); 49 while(T--) 50 { 51 int i,n,m,r=0,c=0; 52 scanf("%d%d",&n,&m); 53 memset(first,0,sizeof(first)); 54 memset(dfn,0,sizeof(dfn)); 55 memset(scc,0,sizeof(scc)); 56 cnt=0;sl=0;cl=0; 57 for(i=1;i<=m;i++) 58 { 59 scanf("%d%d",&t[i].x,&t[i].y); 60 t[i].next=first[t[i].x];first[t[i].x]=i; 61 } 62 for(i=1;i<=n;i++) if(dfn[i]==0) ffind(i); 63 memset(ru,1,sizeof(ru)); 64 memset(chu,1,sizeof(chu)); 65 for(i=1;i<=m;i++) if(scc[t[i].x]!=scc[t[i].y]) 66 chu[scc[t[i].x]]=0,ru[scc[t[i].y]]=0; 67 for(i=1;i<=cl;i++) r+=ru[i],c+=chu[i]; 68 if(cl==1) printf("0 "); 69 else printf("%d ",mymax(r,c)); 70 } 71 return 0; 72 }
2016-03-17 16:46:42