kuangbin专题九 POJ1236 Network of Schools(Tarjan模板题)
2018-01-09 18:20
525 查看
题意:
一些学校连成了网络, 在学校之间存在某个协议:每个学校都维护一张传送表,表明他们要负责将收到的软件传送到表中的所有学校。如果A在B的表中,那么B不一定在A的表中。
现在的任务就是,给出所有学校及他们维护的表,问题(1):如果所有学校都要被传送到,那么需要几份软件;问题(2):如果只传送一份软件,那么需要添加几条边?
题解:
这道题就是求学校之间连成网络的强联通分量,我一开始的想法是用超级源点+朱刘算法求出到底是否联通,联通就输出1,后来发现如果不联通的话就超级麻烦了,看到题解才知道这道题是强连通。那么第一问怎么求呢?如果整个图就是强连通的话就是输出1了,但是不是的话,怎么做呢?只要想他们缩点之后要怎么联通的情况就好了,因为Tarjan算法的特点就是可以把一个强连通分量(强连通分量里面的点相互能到达)缩成点。缩点之后查看一下有几个点的入度为0就是第一问的答案了,为什么?因为如果你入度为0的话就可以知道没有点连接它了。那第二问呢?怎么求呢?我们可以继续从缩点入手,计算他们的入度为0和出度为0的点分别有多少个,然后找出最大那个就可以了。(不理解的自己去画一下图就知道了。)
这道题刚好可以作为我以后的模板来练。
Tarjan的时间复杂度:邻接矩阵存储图,时间复杂度为O(N^2)。因为边的处理就需要N^2的时间,如果改有邻接表存储,算法时间复杂度降为O(M+N)。
模板1参考这位大佬的:
http://blog.csdn.net/huzhengnan/article/details/7787595
模板2(这位大佬的代码简洁啊,但是可能看代码没有代码1的理解好,但是这位大佬解释的很好。)参考这位大佬的:
http://blog.csdn.net/mengxiang000000/article/details/51672725
模板1:
模板2:
一些学校连成了网络, 在学校之间存在某个协议:每个学校都维护一张传送表,表明他们要负责将收到的软件传送到表中的所有学校。如果A在B的表中,那么B不一定在A的表中。
现在的任务就是,给出所有学校及他们维护的表,问题(1):如果所有学校都要被传送到,那么需要几份软件;问题(2):如果只传送一份软件,那么需要添加几条边?
题解:
这道题就是求学校之间连成网络的强联通分量,我一开始的想法是用超级源点+朱刘算法求出到底是否联通,联通就输出1,后来发现如果不联通的话就超级麻烦了,看到题解才知道这道题是强连通。那么第一问怎么求呢?如果整个图就是强连通的话就是输出1了,但是不是的话,怎么做呢?只要想他们缩点之后要怎么联通的情况就好了,因为Tarjan算法的特点就是可以把一个强连通分量(强连通分量里面的点相互能到达)缩成点。缩点之后查看一下有几个点的入度为0就是第一问的答案了,为什么?因为如果你入度为0的话就可以知道没有点连接它了。那第二问呢?怎么求呢?我们可以继续从缩点入手,计算他们的入度为0和出度为0的点分别有多少个,然后找出最大那个就可以了。(不理解的自己去画一下图就知道了。)
这道题刚好可以作为我以后的模板来练。
Tarjan的时间复杂度:邻接矩阵存储图,时间复杂度为O(N^2)。因为边的处理就需要N^2的时间,如果改有邻接表存储,算法时间复杂度降为O(M+N)。
模板1参考这位大佬的:
http://blog.csdn.net/huzhengnan/article/details/7787595
模板2(这位大佬的代码简洁啊,但是可能看代码没有代码1的理解好,但是这位大佬解释的很好。)参考这位大佬的:
http://blog.csdn.net/mengxiang000000/article/details/51672725
模板1:
#include<stdio.h> #include<string.h> #include<string.h> #include<vector> #include<algorithm> using namespace std; const int MAXN=105; int map[MAXN][MAXN]; int low[MAXN]; int dfn[MAXN]; int stack[MAXN],head; int instack[MAXN]; int belong[MAXN]; int in[MAXN],out[MAXN]; int index,sig; int n,m; void init() { memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); memset(belong,0,sizeof(belong)); memset(map,0,sizeof(map)); memset(dfn,-1,sizeof(dfn)); memset(low,0,sizeof(low)); memset(stack,0,sizeof(stack)); memset(instack,0,sizeof(stack)); index=1; sig=0; head=0; } void tarjan(int u) { low[u]=dfn[u]=index; // 刚搜到一个节点时low = dfn index++; stack[++head]=u;// 将该节点入栈 instack[u]=1;// 将入栈标记设置为1 for(int i=1;i<=n;i++) { if(!map[u][i])// 如果两点之间没有边就不用管它了 continue; if(dfn[i]==-1) { tarjan(i);// 类似dfs般搜索这个节点所能到达的节点。 low[u]=min(low[u],low[i]);// 回溯的时候改变当前节点的low值 } else if(instack[i])// 如果搜索到的节点已经被搜索过(即存在回边)而且现在在栈中 { low[u]=min(low[u],dfn[i]);// 更新当前节点的low值,这里的意思是两个节点之间有一条可达边,而前面节点已经在栈中,那么后面的节点就可能和前面的节点在一个联通分量中 } } if(low[u]==dfn[u])// 最终退回来的时候 low[] == dfn[] ,没有节点能将根节点更新,那说明这个点是个关键节点 { // low == dfn 的节点必然就是根节点 int temp; sig++; while(1)// 一直出栈到此节点, 这些元素是一个强联通分量 { temp=stack[head--];// 弹出栈元素 belong[temp]=sig; // 为了方便计算,将强联通分量进行标记 instack[temp]=0;// 将栈内标记置为0 // printf("%d\n",temp); if(temp==u)// 一直弹到u出现为止 break; } // printf("~~~~~~~~~~~~~~~~~~~~~~~\n"); } } void solve() { for(int i=1;i<=n;i++) { if(dfn[i]==-1)// 如果某点没被访问过,则对其进行tarjan tarjan(i);// tarjan的成果是得到了一个belong数组,记录每个节点分别属于哪个强联通分量 } for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(map[i][j]&&belong[i]!=belong[j]) { out[belong[i]]++; in[belong[j]]++; } } } int t1=0,t2=0; for(int i=1;i<=sig;i++) { if(in[i]==0) t1++; if(out[i]==0) t2++; // printf("%d %d %d\n",i,in[i],out[i]); } if(sig==1) printf("1\n0\n"); else printf("%d\n%d\n", t1, max(t1, t2)); } int main() { while(~scanf("%d",&n)) { init(); for(int i=1;i<=n;i++) { while(1) { int v; scanf("%d",&v); if(v==0) break; map[i][v]=1; } } solve(); } return 0; }
模板2:
#include<stdio.h> #include<string.h> #include<vector> #include<algorithm> using namespace std; const int MAXN=105; vector<int>ve[MAXN]; int map[MAXN][MAXN]; int DFN[MAXN]; int low[MAXN]; int stack[MAXN]; int color[MAXN]; int vis[MAXN]; int in[MAXN],out[MAXN]; int n,m,sig,tt,cnt; void init() { memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); memset(DFN,0,sizeof(DFN)); memset(low,0,sizeof(low)); memset(vis,0,sizeof(vis)); memset(stack,0,sizeof(stack)); memset(color,0,sizeof(color)); memset(map,0,sizeof(map)); for(int i=1;i<=n;i++) ve[i].clear(); } void Tarjan(int u) { vis[u]=1; low[u]=DFN[u]=cnt++; stack[++tt]=u; for(int i=0;i<ve[u].size();i++) { int v=ve[u][i]; if(vis[v]==0) Tarjan(v); if(vis[v]==1) low[u]=min(low[u],low[v]); } if(DFN[u]==low[u]) { sig++; do{ color[stack[tt]]=sig; vis[stack[tt]]=-1; }while(stack[tt--]!=u); } } void slove() { cnt=1,tt=-1,sig=0; for(int i=1;i<=n;i++) { if(vis[i]==0) { Tarjan(i); } } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(map[i][j]&&color[i]!=color[j]) { in[color[j]]++; out[color[i]]++; } int t1=0,t2=0; for(int i=1;i<=sig;i++) { if(!in[i]) t1++; if(!out[i]) t2++; } if(sig==1) printf("1\n0\n"); else printf("%d\n%d\n",t1,max(t1,t2)); } int main() { while(~scanf("%d",&n)) { init(); for(int i=1;i<=n;i++) { while(true) { int v; scanf("%d",&v); if(v==0) break; ve[i].push_back(v); map[i][v]=1; } } slove(); } }
相关文章推荐
- POJ1236 - Network of Schools tarjan
- 【强连通分量】Tarjan(缩点)POJ1236-Network of Schools
- poj1236 Network of Schools (tarjan缩点+求入度为0的点和出度为0的点的个数)
- poj1236 Network of Schools【强连通分量(tarjan)缩点】
- POJ1236-Network of Schools(Tarjan + 缩点)
- POJ1236 Network of Schools (Tarjan)
- POJ1236-Network of Schools(Tarjan + 缩点)
- poj1236 Network of Schools(tarjan缩点)
- Network of Schools --POJ1236 Tarjan
- poj1236 Network of Schools(tarjan)
- [POJ1236]Network of Schools(Tarjan缩点+强连通分量)
- Network of Schools --POJ1236 Tarjan
- poj1236 Network of Schools(tarjan缩点)
- POJ1236 Network of Schools【Tarjan】【强连通分量】
- POJ1236 Network of Schools,Tarjan
- poj1236 Network of Schools 【连通图-强联通分量-tarjan】
- poj1236 Network of Schools(强连通分量,tarjan)
- Network of Schools_POJ1236_Tarjan
- 【tarjan+缩点】POJ1236[IOI1996]-Network of Schools
- 【POJ1236】Network of Schools(Tarjan缩点)