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)个点啦.
#include <cstring>
const int Maxn=;
const int Maxm=;
struct EDGE{int to,next;}edge[Maxm<<];
int head[Maxn],Dfn[Maxn],Low[Maxn],Belong[Maxn],In[Maxn],Out[Maxn],Stack[Maxn],Top,vis[Maxn],n,cnt,Stamp,Scc,x;
inline int Max(int x,int y) {return x>y?x:y;}
inline int Min(int x,int y) {return x>y?y:x;}
inline void Add(int u,int v) {edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt++;} void Tarjan(int u,int fa)
{
Low[u]=Dfn[u]=++Stamp; Stack[++Top]=u; vis[u]=true;
for (int i=head[u];i!=-;i=edge[i].next)
{
int v=edge[i].to;
if (v==fa) continue;
if (!Dfn[v])
{
Tarjan(v,u);
Low[u]=Min(Low[u],Low[v]);
} else if (vis[v]) Low[u]=Min(Low[u],Dfn[v]);
}
if (Dfn[u]==Low[u])
{
Scc++; int v=;
while (v!=u)
{
v=Stack[Top--];
vis[v]=false;
Belong[v]=Scc;
}
}
}
int main()
{
// freopen("c.in","r",stdin);
scanf("%d",&n);
memset(head,-,sizeof(head));
for (int i=;i<=n;i++)
while (scanf("%d",&x)&&x)
Add(i,x);
memset(vis,false,sizeof(vis)); Scc=;
for (int i=;i<=n;i++) if (!Dfn[i]) Tarjan(i,);
for (int u=;u<=n;u++)
for (int i=head[u];i!=-;i=edge[i].next)
if (Belong[u]!=Belong[edge[i].to]) In[Belong[edge[i].to]]++,Out[Belong[u]]++;
int Tmp1=,Tmp2=;
for (int i=;i<=Scc;i++)
{
if (In[i]==) Tmp1++;
if (Out[i]==) Tmp2++;
}
if (Scc==)
{
puts("");
puts("");
return ;
}
printf("%d\n",Tmp1);
printf("%d\n",Max(Tmp1,Tmp2));
return ;
}
POJ 1236
POJ 3177
给定一个连通的无向图G,至少要添加几条边,才能使其变为双连通图。
Tarjan缩点后统计叶子节点的个数,给两个相连就可以了 所以Sum=(Ans+1)>>1;
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int Maxn=;
const int Maxm=;
struct EDGE{int to,next;}edge[Maxm<<];
int head[Maxn],Dfn[Maxn],Low[Maxn],vis[Maxn],n,m,u,v,cnt,Top,Stack[Maxn],d[Maxn],Scc,Stamp,Belong[Maxn],Ans;
inline void Add(int u,int v) {edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt++;}
inline int Min(int x,int y) {return x>y?y:x;} void Tarjan(int u,int fa)
{
Dfn[u]=Low[u]=++Stamp; Stack[++Top]=u; vis[u]=true;
for (int i=head[u];i!=-;i=edge[i].next)
{
int v=edge[i].to;
if (i==(fa^)) continue;
if (!Dfn[v])
{
Tarjan(v,i);
Low[u]=Min(Low[u],Low[v]);
} else if (vis[v]) Low[u]=Min(Low[u],Dfn[v]);
}
if (Dfn[u]==Low[u])
{
Scc++;
while (true)
{
int v=Stack[Top--];
vis[v]=false;
Belong[v]=Scc;
if (v==u) break;
}
}
}
int main()
{
scanf("%d%d",&n,&m);
memset(head,-,sizeof(head));
for (int i=;i<=m;i++)
{
scanf("%d%d",&u,&v);
Add(u,v),Add(v,u);
}
for (int i=;i<=n;i++) if (!Dfn[i]) Tarjan(i,-);
for (int u=;u<=n;u++)
{
for (int i=head[u];i!=-;i=edge[i].next)
if (Belong[u]!=Belong[edge[i].to]) d[Belong[u]]++;
}
for (int i=;i<=Scc;i++) if (d[i]==) Ans++;
printf("%d\n",(Ans+)>>);
return ;
}
POJ 3177
POJ 1144
给你一个图,求有多少个割点
u为树根,且u有多于一个子树。 (2) u不为树根,且满足存在(u,v)为树枝边(或称父子边,即u为v在搜索树中的父亲),使得DFS(u)<=Low(v)。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int Maxn=;
const int Maxm=;
struct EDGE{int to,next;}edge[Maxm];
int head[Maxn],Dfn[Maxn],Low[Maxn],Root,Son,u,v,n,cnt,Stamp;
bool Cut[Maxn];
inline int Min(int x,int y) {return x>y?y:x;}
inline void Add(int u,int v) {edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt++;}
void Tarjan(int u)
{
Dfn[u]=Low[u]=++Stamp;
for (int i=head[u];i!=-;i=edge[i].next)
{
int v=edge[i].to;
if (!Dfn[v])
{
Tarjan(v);
if (u==Root) Son++;
else
{
Low[u]=Min(Low[u],Low[v]);
if (Dfn[u]<=Low[v]) Cut[u]=true;
}
} else
Low[u]=Min(Low[u],Dfn[v]);
}
}
int main()
{
while (scanf("%d",&n)!=EOF && n!=)
{
memset(head,-,sizeof(head));
memset(Dfn,,sizeof(Dfn));
memset(Low,,sizeof(Low));
memset(Cut,false,sizeof(Cut)); Stamp=; cnt=;
while (scanf("%d",&u)!=EOF && u!=)
while (getchar()!='\n')
{
scanf("%d",&v);
Add(u,v),Add(v,u);
}
Root=,Son=;
Tarjan();
int Ans=;
if (Son>) Ans=;
for (int i=;i<=n;i++) if (Cut[i]) Ans++;
printf("%d\n",Ans);
}
return ;
}
POJ 1144
POJ 2186
求出度为0的奶牛的个数即可
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int Maxn=;
const int Maxm=;
struct EDGE{int to,next;}edge[Maxm<<];
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];
inline void Add(int u,int v) {edge[cnt].to=v;edge[cnt].next=head[u]; head[u]=cnt++;}
inline int Min(int x,int y) {return x>y?y:x;}
void Tarjan(int u)
{
Dfn[u]=Low[u]=++Stamp; Stack[++Top]=u; vis[u]=true;
for (int i=head[u];i!=-;i=edge[i].next)
{
int v=edge[i].to;
if (!Dfn[v])
{
Tarjan(v);
Low[u]=Min(Low[u],Low[v]);
} else
if (vis[v])
Low[u]=Min(Low[u],Dfn[v]);
}
if (Dfn[u]==Low[u])
{
Scc++;
int v=;
while (v!=u)
{
v=Stack[Top--];
Belong[v]=Scc,++Size[Scc];
vis[v]=false;
}
}
}
int main()
{
scanf("%d%d",&n,&m);
memset(head,-,sizeof(head));
for (int i=;i<=m;i++)
{
scanf("%d%d",&u,&v);
Add(u,v);
}
for (int i=;i<=n;i++)
if (!Dfn[i]) Tarjan(i);
for (int u=;u<=n;u++)
{
for (int i=head[u];i!=-;i=edge[i].next)
if (Belong[u]!=Belong[edge[i].to]) Out[Belong[u]]++;
}
int Zero=,k=;
for (int i=;i<=Scc;i++)
if (!Out[i])
{
Zero++;
k=Size[i];
}
Zero>?puts(""):printf("%d\n",k);
return ;
}
POJ2186
POJ 3352
一个连通的无向图,求至少需要添加几条边,救能保证删除任意一条边,图仍然是连通的,即成为双连通分量
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int Maxn=;
const int Maxm=;
struct EDGE{int to,next;}edge[Maxm<<];
int head[Maxn],Dfn[Maxn],Low[Maxn],vis[Maxn],n,m,u,v,cnt,Top,Stack[Maxn],d[Maxn],Scc,Stamp,Belong[Maxn],Ans;
inline void Add(int u,int v) {edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt++;}
inline int Min(int x,int y) {return x>y?y:x;}
void Tarjan(int u,int fa)
{
Dfn[u]=Low[u]=++Stamp; Stack[++Top]=u; vis[u]=true;
for (int i=head[u];i!=-;i=edge[i].next)
{
int v=edge[i].to;
if (v==fa) continue;
if (!Dfn[v] && !vis[v])
{
Tarjan(v,u);
Low[u]=Min(Low[u],Low[v]);
} else if (vis[v]) Low[u]=Min(Low[u],Dfn[v]);
}
if (Dfn[u]==Low[u])
{
Scc++;
while (Stack[Top]!=u && Top>=) Belong[Stack[Top--]]=Scc;
Belong[Stack[Top--]]=Scc;
}
}
int main()
{
scanf("%d%d",&n,&m);
memset(head,-,sizeof(head));
for (int i=;i<=m;i++)
{
scanf("%d%d",&u,&v);
Add(u,v),Add(v,u);
}
Tarjan(,);
for (int u=;u<=n;u++)
{
for (int i=head[u];i!=-;i=edge[i].next)
if (Belong[u]!=Belong[edge[i].to]) d[Belong[edge[i].to]]++;
} for (int i=;i<=Scc;i++) if (d[i]==) Ans++;
printf("%d\n",(Ans+)>>);
return ;
}
POJ 3352
HDU 3394
一个无向图(可能不连通)有n个点和m条边.现在要你找出冲突边和多余边的数目.其中冲突边是那些同时存在于多个环中的边,而多余边是不在任何一个环中的边.当点数=边数,形成一个环,当点数>边数(一条线段,说明这条边是桥),当点数<边数,那么就含1个以上的环了
#include <cstdio>
#include <cstring>
const int Maxn=;
const int Maxm=;
const int Inf=0x3f3f3f3f;
int Low[Maxn],Dfn[Maxn],Bcc[Maxn],vis[Maxn],Stamp,Top,cnt,u,v,Bridge,Way;
int head[Maxn],Stack[Maxn],n,m,belong[Maxn];
struct EDGE{int to,next;}edge[Maxm<<];
inline int Min(int x,int y) {return x>y?y:x;}
inline void Add(int u,int v)
{edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt++;}
inline void CirCuit()
{
int Cnt=;
memset(belong,false,sizeof(belong));
for (int i=;i<=Bcc[];i++) belong[Bcc[i]]=true;
for (int j=;j<=Bcc[];j++)
{
int u=Bcc[j];
for (int i=head[u];i!=-;i=edge[i].next)
if (belong[edge[i].to]) Cnt++;
}
Cnt>>=;
if (Cnt>Bcc[]) Way+=Cnt;
}
void Tarjan(int u,int fa)
{
Low[u]=Dfn[u]=++Stamp; Stack[++Top]=u; vis[u]=true;
for (int i=head[u];i!=-;i=edge[i].next)
{
int v=edge[i].to;
if (fa==(i^)) continue;
if (!Dfn[v])
{
Tarjan(v,i);
Low[u]=Min(Low[u],Low[v]);
if (Low[v]>=Dfn[u])
{
if (Low[v]>Dfn[u]) Bridge++;
Bcc[]=;
while (true)
{
int x=Stack[Top--];
Bcc[++Bcc[]]=x;
if (x==v) break;
}
Bcc[++Bcc[]]=u;
CirCuit();
}
} else if (vis[v]) Low[u]=Min(Low[u],Dfn[v]);
}
}
int main()
{
while (scanf("%d%d",&n,&m)!=EOF)
{
if (n== && m==) break;
cnt=; memset(head,-,sizeof(head));
memset(Dfn,,sizeof(Dfn)); Top=;
memset(Low,,sizeof(Low)); Stamp=;
memset(vis,false,sizeof(vis));
Bridge=Way=;
for (int i=;i<=m;i++)
{
scanf("%d%d",&u,&v);
Add(u,v),Add(v,u);
}
for (int i=;i<=n;i++) if (!Dfn[i]) Tarjan(i,-);
printf("%d %d\n",Bridge,Way);
}
return ;
}
HDU 3394
NOIP 考前 Tarjan复习的更多相关文章
- noip考前模板复习
网络流 Dinic(搭配飞行员) //Serene #include<algorithm> #include<iostream> #include<cstring> ...
- NOIP 考前 队列复习
BZOJ 1127 #include <cstdio> #include <cstring> #include <iostream> #include <al ...
- NOIP 考前 数论复习
POJ 2891 x=r1 (mod a1) x=r2 (mod a2) x=a1*x+r1,x=a2*y+r2; a1*x-a2*y=r2-r1; 用Extend_Gcd求出m1*x+m2*y=d; ...
- NOIP 考前 数据结构复习
BZOJ 1455 左偏树即可 #include <cstdio> #define LL long long ; struct Info{LL l,r,v,Dis;}Tree[Maxn]; ...
- NOIP 考前DP 复习
POJ 2533 最长不降子序列 #include <cstdio> ; int a[Maxn],Pos[Maxn],F[Maxn],n,Ans; inline int Max(int x ...
- NOIP考前划水
NOIP考前划水 君指先跃动の光は.私の一生不変の信仰に.唯私の超電磁砲永世生き! 要开始背配置了? 3行不谢. (setq c-default-style "awk") (glo ...
- Noip前的大抱佛脚----Noip真题复习
Noip前的大抱佛脚----Noip真题复习 Tags: Noip前的大抱佛脚 Noip2010 题目不难,但是三个半小时的话要写四道题还是需要码力,不过按照现在的实力应该不出意外可以AK的. 机器翻 ...
- tarjan复习笔记
tarjan复习笔记 (关于tarjan读法,优雅一点读塔洋,接地气一点读塔尖) 0. 连通分量 有向图: 强连通分量(SCC)是个啥 就是一张图里面两个点能互相达到,那么这两个点在同一个强连通分量里 ...
- NOIP 考前 并查集复习
POJ 1182 把一个点拆成x,x+n,x+2*n,x吃y可以表示认为x,y+n是一类的,x+n,y+2*n是一类,x+2*n,y是一类. #include <cstdio> ; ],n ...
随机推荐
- 从下往上看--新皮层资料的读后感 第三部分 70年前的逆向推演- 从NN到ANN
第三部分 NN-ANN 70年前的逆向推演 从这部分开始,调整一下视角主要学习神经网络算法,将其与生物神经网络进行横向的比较,以窥探一二. 现在基于NN的AI应用几乎是满地都是,效果也不错,这种貌似神 ...
- .net乱码问题
最近在给一个客户做framwwork版本升级,从1.0版本升级到4.0版本,发现最大的问题就是乱码. 在1.0版本下,gb2312编码能够运行得很好,可是升级到4.0后就都是乱码. 随后将webcon ...
- Tomcat version 7.0 only supports J2EE 1.2, 1.3, 1.4, and Java EE 5 and 6 Web modules
解决方案: 找到如下文件 将"jst.web"的version改低一些
- Linux下面CentOS 7桌面的安装
搭建本地yum仓库的方法 http://www.cnblogs.com/lql123/p/5952788.html 1.yum grouplist #列出yum仓库里的软件组列表 2.yum grou ...
- Process Explorer使用图文教程
这是一款由Sysinternals开发的Windows系统和应用程序监视工具,目前Sysinternals已经被微软收购,此款不仅结合了文件监视和注册表监视两个工具的功能,还增加了多项重要的增强功能, ...
- 关于ADO.NET 超时的问题
前几天超时问题困扰我很头疼. 为什么我设置了链接字符串的超时时间很长,可是等了一小会就报错Timeout了? connectionString="Data Source=.;Initial ...
- Jaxb annotation使用
JAXB(Java Architecture for XML Binding) 是一个业界的标准,是一项可以根据XML Schema产生Java类的技术.该过程中,JAXB也提供了将XML实例文档反向 ...
- html生成图片并保存到本地方法(Windows)
// 最近用到一个保存html为图片到本地的功能(保存到下载目录),记之,该功能IE使用Blob 存储数据,关于兼容性问题参见如下表格,其他浏览器使用a标签download属性新功能下载 Browse ...
- java 创建线程的三种方法Callable,Runnable,Thread比较及用法
转自:http://www.chinaitlab.com/Java/line/942440.html 编写多线程程序是为了实现多任务的并发执行,从而能够更好地与用户交互.一般有三种方法,Thread, ...
- Flapper Bird的学习笔记(一)
因为我有一个超屌的梦想,所以就绝不做孬种的追梦人! 本文主要目的是为了实现Flapper Bird的功能. 另外一个目的是为了加强对Unity引擎的理解和掌握. 新人一枚,如若看到是我幸运.若是发现错 ...