POJ 1236
给定一个有向图,求:
1) 至少要选几个顶点,才能做到从这些顶点出发,可以到达全部顶点
2) 至少要加多少条边,才能使得从任何一个顶点出发,都能到达全部顶点
第一个就是缩点之后有多少入度为0的个数因为一定要从这些节点出发
第二个就是因为图本身就是联通的,设入度为0的点有n个,出度为0的点有m个,
那么入度的编号为N0,N1,N2,N3...Nn,出度编号为M0,M1,M2...Mm
那么连N0->M0->N1->M1->N2->M3。这样形成环啦那连到Min(n,m)时就会结束了剩下的Abs(n-m)点,连起来就有Max(n,m)个点啦.
1 #include <cstring> 2 const int Maxn=110; 3 const int Maxm=10010; 4 struct EDGE{int to,next;}edge[Maxm<<2]; 5 int head[Maxn],Dfn[Maxn],Low[Maxn],Belong[Maxn],In[Maxn],Out[Maxn],Stack[Maxn],Top,vis[Maxn],n,cnt,Stamp,Scc,x; 6 inline int Max(int x,int y) {return x>y?x:y;} 7 inline int Min(int x,int y) {return x>y?y:x;} 8 inline void Add(int u,int v) {edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt++;} 9 10 void Tarjan(int u,int fa) 11 { 12 Low[u]=Dfn[u]=++Stamp; Stack[++Top]=u; vis[u]=true; 13 for (int i=head[u];i!=-1;i=edge[i].next) 14 { 15 int v=edge[i].to; 16 if (v==fa) continue; 17 if (!Dfn[v]) 18 { 19 Tarjan(v,u); 20 Low[u]=Min(Low[u],Low[v]); 21 } else if (vis[v]) Low[u]=Min(Low[u],Dfn[v]); 22 } 23 if (Dfn[u]==Low[u]) 24 { 25 Scc++; int v=0; 26 while (v!=u) 27 { 28 v=Stack[Top--]; 29 vis[v]=false; 30 Belong[v]=Scc; 31 } 32 } 33 } 34 int main() 35 { 36 // freopen("c.in","r",stdin); 37 scanf("%d",&n); 38 memset(head,-1,sizeof(head)); 39 for (int i=1;i<=n;i++) 40 while (scanf("%d",&x)&&x) 41 Add(i,x); 42 memset(vis,false,sizeof(vis)); Scc=0; 43 for (int i=1;i<=n;i++) if (!Dfn[i]) Tarjan(i,1); 44 for (int u=1;u<=n;u++) 45 for (int i=head[u];i!=-1;i=edge[i].next) 46 if (Belong[u]!=Belong[edge[i].to]) In[Belong[edge[i].to]]++,Out[Belong[u]]++; 47 int Tmp1=0,Tmp2=0; 48 for (int i=1;i<=Scc;i++) 49 { 50 if (In[i]==0) Tmp1++; 51 if (Out[i]==0) Tmp2++; 52 } 53 if (Scc==1) 54 { 55 puts("1"); 56 puts("0"); 57 return 0; 58 } 59 printf("%d ",Tmp1); 60 printf("%d ",Max(Tmp1,Tmp2)); 61 return 0; 62 }
POJ 3177
给定一个连通的无向图G,至少要添加几条边,才能使其变为双连通图。
Tarjan缩点后统计叶子节点的个数,给两个相连就可以了 所以Sum=(Ans+1)>>1;
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 using namespace std; 6 const int Maxn=5100; 7 const int Maxm=10010; 8 struct EDGE{int to,next;}edge[Maxm<<2]; 9 int head[Maxn],Dfn[Maxn],Low[Maxn],vis[Maxn],n,m,u,v,cnt,Top,Stack[Maxn],d[Maxn],Scc,Stamp,Belong[Maxn],Ans; 10 inline void Add(int u,int v) {edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt++;} 11 inline int Min(int x,int y) {return x>y?y:x;} 12 13 void Tarjan(int u,int fa) 14 { 15 Dfn[u]=Low[u]=++Stamp; Stack[++Top]=u; vis[u]=true; 16 for (int i=head[u];i!=-1;i=edge[i].next) 17 { 18 int v=edge[i].to; 19 if (i==(fa^1)) continue; 20 if (!Dfn[v]) 21 { 22 Tarjan(v,i); 23 Low[u]=Min(Low[u],Low[v]); 24 } else if (vis[v]) Low[u]=Min(Low[u],Dfn[v]); 25 } 26 if (Dfn[u]==Low[u]) 27 { 28 Scc++; 29 while (true) 30 { 31 int v=Stack[Top--]; 32 vis[v]=false; 33 Belong[v]=Scc; 34 if (v==u) break; 35 } 36 } 37 } 38 int main() 39 { 40 scanf("%d%d",&n,&m); 41 memset(head,-1,sizeof(head)); 42 for (int i=1;i<=m;i++) 43 { 44 scanf("%d%d",&u,&v); 45 Add(u,v),Add(v,u); 46 } 47 for (int i=1;i<=n;i++) if (!Dfn[i]) Tarjan(i,-1); 48 for (int u=1;u<=n;u++) 49 { 50 for (int i=head[u];i!=-1;i=edge[i].next) 51 if (Belong[u]!=Belong[edge[i].to]) d[Belong[u]]++; 52 } 53 for (int i=1;i<=Scc;i++) if (d[i]==1) Ans++; 54 printf("%d ",(Ans+1)>>1); 55 return 0; 56 }
POJ 1144
给你一个图,求有多少个割点
u为树根,且u有多于一个子树。 (2) u不为树根,且满足存在(u,v)为树枝边(或称父子边,即u为v在搜索树中的父亲),使得DFS(u)<=Low(v)。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 const int Maxn=1010; 7 const int Maxm=2001000; 8 struct EDGE{int to,next;}edge[Maxm]; 9 int head[Maxn],Dfn[Maxn],Low[Maxn],Root,Son,u,v,n,cnt,Stamp; 10 bool Cut[Maxn]; 11 inline int Min(int x,int y) {return x>y?y:x;} 12 inline void Add(int u,int v) {edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt++;} 13 void Tarjan(int u) 14 { 15 Dfn[u]=Low[u]=++Stamp; 16 for (int i=head[u];i!=-1;i=edge[i].next) 17 { 18 int v=edge[i].to; 19 if (!Dfn[v]) 20 { 21 Tarjan(v); 22 if (u==Root) Son++; 23 else 24 { 25 Low[u]=Min(Low[u],Low[v]); 26 if (Dfn[u]<=Low[v]) Cut[u]=true; 27 } 28 } else 29 Low[u]=Min(Low[u],Dfn[v]); 30 } 31 } 32 int main() 33 { 34 while (scanf("%d",&n)!=EOF && n!=0) 35 { 36 memset(head,-1,sizeof(head)); 37 memset(Dfn,0,sizeof(Dfn)); 38 memset(Low,0,sizeof(Low)); 39 memset(Cut,false,sizeof(Cut)); Stamp=0; cnt=0; 40 while (scanf("%d",&u)!=EOF && u!=0) 41 while (getchar()!=' ') 42 { 43 scanf("%d",&v); 44 Add(u,v),Add(v,u); 45 } 46 Root=1,Son=0; 47 Tarjan(1); 48 int Ans=0; 49 if (Son>1) Ans=1; 50 for (int i=1;i<=n;i++) if (Cut[i]) Ans++; 51 printf("%d ",Ans); 52 } 53 return 0; 54 }
POJ 2186
求出度为0的奶牛的个数即可
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 using namespace std; 6 const int Maxn=10100; 7 const int Maxm=50100; 8 struct EDGE{int to,next;}edge[Maxm<<1]; 9 int n,m,Dfn[Maxn],Low[Maxn],head[Maxn],Stack[Maxn],Belong[Maxn],Scc,Stamp,cnt,Top,u,v,Out[Maxn],vis[Maxn],Size[Maxn]; 10 inline void Add(int u,int v) {edge[cnt].to=v;edge[cnt].next=head[u]; head[u]=cnt++;} 11 inline int Min(int x,int y) {return x>y?y:x;} 12 void Tarjan(int u) 13 { 14 Dfn[u]=Low[u]=++Stamp; Stack[++Top]=u; vis[u]=true; 15 for (int i=head[u];i!=-1;i=edge[i].next) 16 { 17 int v=edge[i].to; 18 if (!Dfn[v]) 19 { 20 Tarjan(v); 21 Low[u]=Min(Low[u],Low[v]); 22 } else 23 if (vis[v]) 24 Low[u]=Min(Low[u],Dfn[v]); 25 } 26 if (Dfn[u]==Low[u]) 27 { 28 Scc++; 29 int v=0; 30 while (v!=u) 31 { 32 v=Stack[Top--]; 33 Belong[v]=Scc,++Size[Scc]; 34 vis[v]=false; 35 } 36 } 37 } 38 int main() 39 { 40 scanf("%d%d",&n,&m); 41 memset(head,-1,sizeof(head)); 42 for (int i=1;i<=m;i++) 43 { 44 scanf("%d%d",&u,&v); 45 Add(u,v); 46 } 47 for (int i=1;i<=n;i++) 48 if (!Dfn[i]) Tarjan(i); 49 for (int u=1;u<=n;u++) 50 { 51 for (int i=head[u];i!=-1;i=edge[i].next) 52 if (Belong[u]!=Belong[edge[i].to]) Out[Belong[u]]++; 53 } 54 int Zero=0,k=0; 55 for (int i=1;i<=Scc;i++) 56 if (!Out[i]) 57 { 58 Zero++; 59 k=Size[i]; 60 } 61 Zero>1?puts("0"):printf("%d ",k); 62 return 0; 63 }
POJ 3352
一个连通的无向图,求至少需要添加几条边,救能保证删除任意一条边,图仍然是连通的,即成为双连通分量
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 using namespace std; 6 const int Maxn=1100; 7 const int Maxm=10010; 8 struct EDGE{int to,next;}edge[Maxm<<2]; 9 int head[Maxn],Dfn[Maxn],Low[Maxn],vis[Maxn],n,m,u,v,cnt,Top,Stack[Maxn],d[Maxn],Scc,Stamp,Belong[Maxn],Ans; 10 inline void Add(int u,int v) {edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt++;} 11 inline int Min(int x,int y) {return x>y?y:x;} 12 void Tarjan(int u,int fa) 13 { 14 Dfn[u]=Low[u]=++Stamp; Stack[++Top]=u; vis[u]=true; 15 for (int i=head[u];i!=-1;i=edge[i].next) 16 { 17 int v=edge[i].to; 18 if (v==fa) continue; 19 if (!Dfn[v] && !vis[v]) 20 { 21 Tarjan(v,u); 22 Low[u]=Min(Low[u],Low[v]); 23 } else if (vis[v]) Low[u]=Min(Low[u],Dfn[v]); 24 } 25 if (Dfn[u]==Low[u]) 26 { 27 Scc++; 28 while (Stack[Top]!=u && Top>=1) Belong[Stack[Top--]]=Scc; 29 Belong[Stack[Top--]]=Scc; 30 } 31 } 32 int main() 33 { 34 scanf("%d%d",&n,&m); 35 memset(head,-1,sizeof(head)); 36 for (int i=1;i<=m;i++) 37 { 38 scanf("%d%d",&u,&v); 39 Add(u,v),Add(v,u); 40 } 41 Tarjan(1,0); 42 for (int u=1;u<=n;u++) 43 { 44 for (int i=head[u];i!=-1;i=edge[i].next) 45 if (Belong[u]!=Belong[edge[i].to]) d[Belong[edge[i].to]]++; 46 } 47 48 for (int i=1;i<=Scc;i++) if (d[i]==1) Ans++; 49 printf("%d ",(Ans+1)>>1); 50 return 0; 51 }
HDU 3394
一个无向图(可能不连通)有n个点和m条边.现在要你找出冲突边和多余边的数目.其中冲突边是那些同时存在于多个环中的边,而多余边是不在任何一个环中的边.当点数=边数,形成一个环,当点数>边数(一条线段,说明这条边是桥),当点数<边数,那么就含1个以上的环了
1 #include <cstdio> 2 #include <cstring> 3 const int Maxn=10100; 4 const int Maxm=100100; 5 const int Inf=0x3f3f3f3f; 6 int Low[Maxn],Dfn[Maxn],Bcc[Maxn],vis[Maxn],Stamp,Top,cnt,u,v,Bridge,Way; 7 int head[Maxn],Stack[Maxn],n,m,belong[Maxn]; 8 struct EDGE{int to,next;}edge[Maxm<<2]; 9 inline int Min(int x,int y) {return x>y?y:x;} 10 inline void Add(int u,int v) 11 {edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt++;} 12 inline void CirCuit() 13 { 14 int Cnt=0; 15 memset(belong,false,sizeof(belong)); 16 for (int i=1;i<=Bcc[0];i++) belong[Bcc[i]]=true; 17 for (int j=1;j<=Bcc[0];j++) 18 { 19 int u=Bcc[j]; 20 for (int i=head[u];i!=-1;i=edge[i].next) 21 if (belong[edge[i].to]) Cnt++; 22 } 23 Cnt>>=1; 24 if (Cnt>Bcc[0]) Way+=Cnt; 25 } 26 void Tarjan(int u,int fa) 27 { 28 Low[u]=Dfn[u]=++Stamp; Stack[++Top]=u; vis[u]=true; 29 for (int i=head[u];i!=-1;i=edge[i].next) 30 { 31 int v=edge[i].to; 32 if (fa==(i^1)) continue; 33 if (!Dfn[v]) 34 { 35 Tarjan(v,i); 36 Low[u]=Min(Low[u],Low[v]); 37 if (Low[v]>=Dfn[u]) 38 { 39 if (Low[v]>Dfn[u]) Bridge++; 40 Bcc[0]=0; 41 while (true) 42 { 43 int x=Stack[Top--]; 44 Bcc[++Bcc[0]]=x; 45 if (x==v) break; 46 } 47 Bcc[++Bcc[0]]=u; 48 CirCuit(); 49 } 50 } else if (vis[v]) Low[u]=Min(Low[u],Dfn[v]); 51 } 52 } 53 int main() 54 { 55 while (scanf("%d%d",&n,&m)!=EOF) 56 { 57 if (n==0 && m==0) break; 58 cnt=0; memset(head,-1,sizeof(head)); 59 memset(Dfn,0,sizeof(Dfn)); Top=0; 60 memset(Low,0,sizeof(Low)); Stamp=0; 61 memset(vis,false,sizeof(vis)); 62 Bridge=Way=0; 63 for (int i=1;i<=m;i++) 64 { 65 scanf("%d%d",&u,&v); 66 Add(u,v),Add(v,u); 67 } 68 for (int i=1;i<=n;i++) if (!Dfn[i]) Tarjan(i,-1); 69 printf("%d %d ",Bridge,Way); 70 } 71 return 0; 72 }