题意:有多个命题,需要证明他们可以互相推出,现在已经有一些证明关系即 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