zoukankan      html  css  js  c++  java
  • NOIP 考前 Tarjan复习

    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 1236

    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 3177

    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 1144

    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 }
    POJ2186

    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 }
    POJ 3352

    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 }
    HDU 3394
  • 相关阅读:
    淘宝放大镜
    碰撞的小球
    模拟微博发布
    CSS兼容IE Firefox问题与解决方法
    太阳八大行星运行轨迹
    Canvas标签基础
    offsetTop、clientTop、scrollTop、offsetTop
    js绘制圆形时钟
    js时钟
    js五星好评2
  • 原文地址:https://www.cnblogs.com/yyjxx2010xyu/p/6007569.html
Copyright © 2011-2022 走看看