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 ...
随机推荐
- C/C++回调函数
C/C++回调函数 在理解“回调函数”之前,首先讨论下函数指针的概念. 函数指针 (1)概念:指针是一个变量,是用来指向内存地址的.一个程序运行时,所有和运行相关的物件都是需要加载到内存中,这就决定了 ...
- SSL/TLS协议运行机制的概述
互联网的通信安全,建立在SSL/TLS协议之上. 本文简要介绍SSL/TLS协议的运行机制.文章的重点是设计思想和运行过程,不涉及具体的实现细节.如果想了解这方面的内容,请参阅RFC文档. 一.作用 ...
- jboss设置图片上传大小
<http-listener name="default" socket-binding="http" max-post-size="10485 ...
- whereis 和which
这两个命令用的好,可以很快找出文件的路径 [root@oc3408554812 zip-3.0]# which passwd/usr/bin/passwd[root@oc3408554812 zip- ...
- 利用flash精确定位asp.net的图像热点区域
Asp.net的热点区域控件非常有用,但是对于热点区域如何精确定位,设定矩形,圆和多边形要素点的位置,用flash能够精确定位,在flash中制作热点区域的部分,可以是矩形,图形或者文字,然后对于这部 ...
- Android FragmentTransactionExtended:使Fragment以多种样式动画切换
有多种fragment之间切换的效果,效果是这样的: Demo的实现是很简单的. 在res/values中,新建一个arrays.xml文件,存放Fragment动画效果的名称,在spinner中使用 ...
- hadoop机架感知与网络拓扑分析:NetworkTopology和DNSToSwitchMapping
hadoop网络拓扑结构在整个系统中具有很重要的作用,它会影响DataNode的启动(注册).MapTask的分配等等.了解网络拓扑对了解整个hadoop的运行会有很大帮助. 首先通过下面两个图来了解 ...
- (原创)如何使用selenium 驱动chrome浏览器并且打开方式为手机模式-转载请注明出处
随着移动设备使用率的不断增加,移动页面的测试也变得越来越重要. 对于互联网公司M站的测试,如果不通过专用的appium等移动端测试工具是否还有方便快捷的办法呢?答案当然是有啊. 使用chrome dr ...
- android 取消edittext焦点
页面中如果有EditText会默认获取焦点,如果进入页面时不想让其获取到焦点可以按如下步骤: 1.在布局的最外层添加属性: android:focusable="true" and ...
- git检出与创建的过程
Command line instructions Git global setup git config --global user.name "bingo" git confi ...