Network of Schools(强连通分量缩点(邻接表&矩阵))
Description
in the distribution list of school A, then A does not necessarily appear in the list of school B
You are to write a program that computes the minimal number of schools that must receive a copy of the new software in order for the software to reach all schools in the network according to the agreement (Subtask A). As a further task, we want to ensure that
by sending the copy of new software to an arbitrary school, this software will reach all schools in the network. To achieve this goal we may have to extend the lists of receivers by new members. Compute the minimal number of extensions that have to be made
so that whatever school we send the new software to, it will reach all other schools (Subtask B). One extension means introducing one new member into the list of receivers of one school.
Input
the identifiers of the receivers of school i. Each list ends with a 0. An empty list contains a 0 alone in the line.
Output
Sample Input
5
2 4 3 0
4 5 0
0
0
1 0
Sample Output
1
2
开始用桥来判断是不是同一个连通分量,结果果断错了,其实下图应该就会出错
原因是通过头插法先遍历3,结果3的出度为0,由于2通向3已经访问过,因此不能在访问,因此2-->3的路没有标志cut,没法统计这天边的出入度情况,因此出度为0的变为2个了,正确答案应该是1个,所以错了,不能企图通过桥来算出出度入度
错误代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MOD 100000
#define inf 1<<29
#define LL long long
#define MAXN 20010
#define MAXM = 50010
using namespace std;
struct Edge
{
int to,next;
bool cut;
} edge[MAXN]; int head[MAXN],tot;
int low[MAXN],DFN[MAXN],belong[MAXN];///belong 的值为1-block
int index,top,fenzhiNum;
int block ; ///强连通分量
bool inStack[MAXN];
int bridgeNum; ///桥的数目
int stack[MAXN];
int vis[MAXN];
int inans,outans;
int outdu[MAXN];
int indu[MAXN]; void addedge(int u,int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
edge[tot].cut = false;
head[u] = tot++ ;
}
void ini(){
index = block = top = fenzhiNum = 0;
inans = 0, outans = 0 ;
memset(DFN,0,sizeof(DFN));
memset(inStack,false,sizeof(inStack));
memset(vis,0,sizeof(vis));
memset(outdu,0,sizeof(outdu));
memset(indu,0,sizeof(indu));
}
void Tarjan(int u)
{
vis[u] = true;
int v;
low[u] = DFN[u] = ++index;
stack[top++] = u;
inStack[u] = true;
for(int i=head[u] ; i!=-1 ; i=edge[i].next)
{
v = edge[i].to;
//if( v == pre ) continue; ///因为是无向图,所以两条是双向的,所以只遍历一条就够了
if( !DFN[v] )
{
Tarjan(v );
if(low[u]>low[v])
low[u] = low[v];
if(low[v] > DFN[u] ){
bridgeNum++;
edge[i].cut = true;
//edge[i^1].cut = true; ///将两条双向边都设置为桥
} }
else if( inStack[v] && low[u] > DFN[v])
low[u] = DFN[v];
}
if(low[u] == DFN[u])
{
block++;
do
{
v=stack[--top]; ///清空当前强连通分量栈 必须清空
inStack[v] = false;
belong[v]=block; ///v节点都编号为block 也就是这是一个块
}
while(v!=u);
}
} void solve(int N)
{
ini();
for(int i=1;i<=N;i++)
if(!vis[i])
Tarjan(i);
for(int i=1; i<=N ; i++){ ///缩点
for(int j=head[i] ; j!=-1 ; j=edge[j].next)
if( edge[j].cut)//belong[i]!=belong[ edge[j].to ])//edge[j].cut )
indu[ belong[ edge[j].to ] ]++,outdu[ belong[i] ]++ ;
}
for(int i=1;i<=block ;i++)
if(indu[i] == 0)
inans++;
for(int i=1;i<=block ;i++)
if(outdu[i] == 0)
outans++;
// printf("indu=%d,outdu=%d\n",inans,outans);
if(block == 1) printf("1\n0\n");
else printf("%d\n%d\n",inans,max(inans,outans));
//printf("%d\n",(ans+1)/2 );
} int main ()
{
int n,m;
while(~scanf("%d",&n))
{
int u,v,mark=0;
tot=0;
memset(head,-1,sizeof(head));
for(int i=1; i<=n; i++)
{
while(scanf("%d",&u)&&u!=0){
mark=0;
for(int j=head[i] ; j!=-1 ; j=edge[j].next) ///去重边
if(edge[j].to == u){
mark = 1;
break;
}
if(!mark) addedge(i,u);
}
}
solve(n);
}
return 0;
}
正确代码矩阵:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXV 110
#define min(a,b) (a>b?b:a)
#define max(a,b) (a>b?a:b) int n,map[MAXV][MAXV],outdegree[MAXV],indegree[MAXV];
int dfn[MAXV]; //第一次访问的步数
int low[MAXV]; //子树中最早的步数
int stap[MAXV],stop; //模拟栈
bool instack[MAXV]; //是否在栈中
int count; //记录连通分量的个数
int cnt; //记录搜索步数
int belong[MAXV]; //属于哪个连通分量 void init(){
count=stop=cnt=0;
memset(instack,false,sizeof(instack));
memset(map,0,sizeof(map));
memset(dfn,0,sizeof(dfn));
} void tarjan(int x){
int i;
dfn[x]=low[x]=++cnt;
stap[stop++]=x;
instack[x]=true;
for(i=1;i<=n;i++){
if(!map[x][i]) continue;
if(!dfn[i]){
tarjan(i);
low[x]=min(low[i],low[x]);
}else if(instack[i])
low[x]=min(dfn[i],low[x]);
//与x相连,但是i已经被访问过,且还在栈中
//用子树节点更新节点第一次出现的时间
} if(low[x]==dfn[x]){
count++;
while(1){
int tmp=stap[--stop];
belong[tmp]=count;
instack[tmp]=false;
if(tmp==x) break;
}
}
} void output(){
int i,j,inzero=0,outzero=0;
for(i=1;i<=n;i++){
indegree[i]=outdegree[i]=0;
}
for(i=1;i<=n;i++) //找连通分量入度与出度
for(j=1;j<=n;j++)
if(map[i][j] && belong[i]!=belong[j]){
indegree[belong[j]]++;
outdegree[belong[i]]++;
}
for(i=1;i<=count;i++){ //找入度与出度为0的点
if(!indegree[i]) inzero++;
if(!outdegree[i]) outzero++;
} if(count==1) //只有1个结点要特判
printf("1\n0\n");
else
printf("%d\n%d\n",inzero,max(inzero,outzero));
} int main(){
int i,a;
while(~scanf("%d",&n)){
init();
for(i=1;i<=n;i++){
while(scanf("%d",&a) && a) map[i][a]=1;
}
for(i=1;i<=n;i++)
if(!dfn[i]) tarjan(i);
output();
}
return 0;
}
正确代码邻接表
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MOD 100000
#define inf 1<<29
#define LL long long
#define MAXN 20010
#define MAXM = 50010
using namespace std;
struct Edge
{
int to,next;
bool cut;
} edge[MAXN]; int head[MAXN],tot;
int low[MAXN],DFN[MAXN],belong[MAXN];///belong 的值为1-block
int index,top,fenzhiNum;
int block ; ///强连通分量
bool inStack[MAXN];
int bridgeNum; ///桥的数目
int stack[MAXN];
int vis[MAXN];
int inans,outans;
int outdu[MAXN];
int indu[MAXN]; void addedge(int u,int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
edge[tot].cut = false;
head[u] = tot++ ;
}
void ini(){
index = block = top = fenzhiNum = 0;
inans = 0, outans = 0 ;
memset(DFN,0,sizeof(DFN));
memset(inStack,false,sizeof(inStack));
memset(vis,0,sizeof(vis));
memset(outdu,0,sizeof(outdu));
memset(indu,0,sizeof(indu));
}
void Tarjan(int u)
{
vis[u] = true;
int v;
low[u] = DFN[u] = ++index;
stack[top++] = u;
inStack[u] = true;
for(int i=head[u] ; i!=-1 ; i=edge[i].next)
{
v = edge[i].to;
//if( v == pre ) continue; ///因为是无向图,所以两条是双向的,所以只遍历一条就够了
if( !DFN[v] )
{
Tarjan(v );
if(low[u]>low[v])
low[u] = low[v];
if(low[v] > DFN[u] ){
bridgeNum++;
edge[i].cut = true;
//edge[i^1].cut = true; ///将两条双向边都设置为桥
} }
else if( inStack[v] && low[u] > DFN[v])
low[u] = DFN[v];
}
if(low[u] == DFN[u])
{
block++;
do
{
v=stack[--top]; ///清空当前强连通分量栈 必须清空
inStack[v] = false;
belong[v]=block; ///v节点都编号为block 也就是这是一个块
}
while(v!=u);
}
} void solve(int N)
{
ini();
for(int i=1;i<=N;i++)
if(!vis[i])
Tarjan(i);
for(int i=1; i<=N ; i++){ ///缩点
for(int j=head[i] ; j!=-1 ; j=edge[j].next)
if( belong[i]!=belong[ edge[j].to ] )
indu[ belong[ edge[j].to ] ]++,outdu[ belong[i] ]++ ;
}
for(int i=1;i<=block ;i++)
if(indu[i] == 0)
inans++;
for(int i=1;i<=block ;i++)
if(outdu[i] == 0)
outans++;
// printf("indu=%d,outdu=%d\n",inans,outans);
if(block == 1) printf("1\n0\n");
else printf("%d\n%d\n",inans,max(inans,outans));
//printf("%d\n",(ans+1)/2 );
} int main ()
{
int n,m;
while(~scanf("%d",&n))
{
int u,v,mark=0;
tot=0;
memset(head,-1,sizeof(head));
for(int i=1; i<=n; i++)
{
while(scanf("%d",&u)&&u!=0){
mark=0;
for(int j=head[i] ; j!=-1 ; j=edge[j].next) ///去重边
if(edge[j].to == u){
mark = 1;
break;
}
if(!mark) addedge(i,u);
}
}
solve(n);
}
return 0;
}
Network of Schools(强连通分量缩点(邻接表&矩阵))的更多相关文章
- POJ 1236 Network Of Schools (强连通分量缩点求出度为0的和入度为0的分量个数)
Network of Schools A number of schools are connected to a computer network. Agreements have been dev ...
- POJ1236 Network of Schools —— 强连通分量 + 缩点 + 入出度
题目链接:http://poj.org/problem?id=1236 Network of Schools Time Limit: 1000MS Memory Limit: 10000K Tot ...
- Network of Schools(强连通分量+缩点) (问添加几个点最少点是所有点连接+添加最少边使图强连通)
Network of Schools Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 13801 Accepted: 55 ...
- POJ 1236 Network of Schools (强连通分量缩点求度数)
题意: 求一个有向图中: (1)要选几个点才能把的点走遍 (2)要添加多少条边使得整个图强联通 分析: 对于问题1, 我们只要求出缩点后的图有多少个入度为0的scc就好, 因为有入度的scc可以从其他 ...
- POJ1236Network of Schools[强连通分量|缩点]
Network of Schools Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 16571 Accepted: 65 ...
- poj-1236.network of schools(强连通分量 + 图的入度出度)
Network of Schools Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 27121 Accepted: 10 ...
- [IOI1996] USACO Section 5.3 Network of Schools(强连通分量)
nocow上的题解很好. http://www.nocow.cn/index.php/USACO/schlnet 如何求强连通分量呢?对于此题,可以直接先用floyd,然后再判断. --------- ...
- POJ1236 Network of Schools (强连通分量,注意边界)
A number of schools are connected to a computer network. Agreements have been developed among those ...
- 【强连通分量缩点】poj 1236 Network of Schools
poj.org/problem?id=1236 [题意] 给定一个有向图,求: (1)至少要选几个顶点,才能做到从这些顶点出发,可以到达全部顶点 (2)至少要加多少条边,才能使得从任何一个顶点出发,都 ...
随机推荐
- JavaScript闭包演示
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8" /> <title&g ...
- SQL SERVER XML 学习总结
SQL SERVER XML 学习总结 最新的项目任务要做一个数据同步的功能,这些天都在做技术准备,主要是用到了微软的Service Broker技术,在熟悉使用该技术的同时,又用到了Sql s ...
- 用Bouncy Castle的C#版API产生公钥和私钥
开源API链接地址:The Legion of the Bouncy Castle Bouncy Castle,简称为BC,原本是java的一个开源JCE提供者,后来也提供了C#版本的API,我下载其 ...
- 08 Linux下MySQL的下载、安装及启动
测试环境 主机系统:Win7 64位 虚拟机:VMware® Workstation 11.1.0 虚拟机系统:CentOS 6.5 64位 Kernel 2.6.32-431.e16.x86_6 ...
- 遇到 Error creating the Web Proxy specified in the 'system.net/defaultProxy' configuration section的解决办法
用记事本编辑*.EXE.config,在“<system.net>”节点加入<defaultProxy> <proxy usesystemdefault="Fa ...
- 黄聪:WordPress 后台发布文章时提示用户选择分类
很多用户在后台发布文章,常常会忘记选择分类,所以很有必要添加一个提醒功能,如果没有选择分类,点击发布时,就显示一个提示信息.要实现这个功能,只要将下面的代码添加到主题的 functions.php 即 ...
- Linux大文件传输(转)
我们经常需要在机器之间传输文件.比如备份,复制数据等等.这个是很常见,也是很简单的.用scp或者rsync就能很好的完成任务.但是如果文件很大,需要占用一些传输时间的时候,怎样又快又好地完成任务就很重 ...
- 队列(Queue)--环形队列、优先队列和双向队列
1. 队列概述 队列和堆栈都是有序列表,属于抽象型数据类型(ADT),所有加入和删除的动作都发生在不同的两端,并符合First In, First Out(先进先出)的特性. 特性: ·FIFO ·拥 ...
- 补一篇关于Jackson和Gson的文章
一.关于Gson的问题 问题1. 如果对象属性里有[],表示它是一个列表,需要用List对象进行封装,不能用String来定义,不然转不了 问题2. Gson在解析的时候,如果json中有转义字符 \ ...
- 最大期望算法 Expectation Maximization概念
在统计计算中,最大期望(EM,Expectation–Maximization)算法是在概率(probabilistic)模型中寻找参数最大似然估计的算法,其中概率模型依赖于无法观测的隐藏变量(Lat ...