PKU 1236 Network of Schools - 最小点基
来源:互联网 发布:手机壁纸软件哪个好 编辑:程序博客网 时间:2024/06/08 00:48
题目大意:
N个高校之间有一些单向的网络链接(N<100),当发布一个软件时,学校i收到软件时,它可以将软件发送给所有它链接到的学校。现在要求发布一款软件,最少需要发给多少个学校,使得所有学校都可以收到软件(问题A)。最少需要添加多少条单向网络链接,可以使得将软件任意发给一个学校,使得所有学校都可以收到(问题B)。
分析:
我们先来讨论问题A。这个问题在吴文虎的OI图论书上有介绍过,叫做有向图的最小点基。
首先,求出有向图的极大强连通分量,在同一个强连通分量里的学校任意一个收到软件,整个强连通分量里的学校都可以收到。将每个强连通分量缩成一个点,构成一个新的有向无环图。当强连通分量i收到软件,那么i可达的强连通分量都可以收到软件。
我们称入度为0的强连通分量为最高强连通分量。显然,每个最高强连通分量都必须单独发送一次软件,而其他强连通分量都可以通过最高强连通分量到达。所以,最高强连通分量的个数也就是问题A的解。
至于问题B,我猜测是MAX(入度为0的点的个数,出度为0的点的个数),没想到居然对了,也没仔细证明。注意的是,当原图只有一个强连通分量是,问题B的答案是0。
- /*
- PKU1236 Network of Schools
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <memory.h>
- #define clr(a) memset(a,0,sizeof(a))
- #define MAX(a,b) ((a)>(b)?(a):(b))
- #define N 105
- #define M 10005
- typedef struct NodeStr{
- int j;
- struct NodeStr *next;
- }Node;
- Node mem[M*2];
- int memp;
- void addEdge(Node *e[],int i,int j){
- Node *p = &mem[memp++];
- p->next = e[i]; p->j = j; e[i] = p;
- }
- int g_DFS_First;
- void DFS_conn(Node* e[],int i,int mark[],int f[],int* nf){
- int j; Node* p;
- if(mark[i]) return; else mark[i]=1;
- if(!g_DFS_First) f[i]=*nf; //反向搜索,获取连通分量编号
- for(p=e[i];p!=NULL;p=p->next) DFS_conn(e,p->j,mark,f,nf);
- if(g_DFS_First) f[(*nf)++]=i; //正向搜索,获取时间戳
- }
- int Connection(Node* e[],int n,int con[]){
- int i,j,k,mark[N],ncon,time[N],ntime;//time[i]表示时间戳为i的节点
- Node *p,*re[N]; //反向边
- clr(re); //构造反向边邻接表
- for(i=0;i<n;i++) for(p=e[i];p!=NULL;p=p->next) addEdge(re,p->j,i);
- g_DFS_First = 1; //正向DFS,获得时间戳
- clr(mark); clr(time); ntime=0;
- for(i=0;i<n;i++) if(!mark[i]) DFS_conn(e,i,mark,time,&ntime);
- g_DFS_First = 0; //反向DFS,获得强连通分量
- clr(mark); clr(con); ncon=0;
- for(i=n-1;i>=0;i--) if(!mark[time[i]])
- { DFS_conn(re,time[i],mark,con,&ncon); ncon++; }
- return ncon;
- }
- /*
- 收缩强连通分量
- 参数:
- e[]有向图邻接表.返回强连通分量个数m.
- ce[]返回收缩强连通分量后的有向图邻接表[0,m-1],
- con[]返回顶点i所属强连通分量的编号con[i]
- */
- int ShrinkConnection(Node *e[],int n,Node *ce[],int con[]){
- int i,j,k,m; Node *p,*q;
- m=Connection(e,n,con);
- for(i=0;i<m;i++) ce[i]=NULL;
- for(k=0;k<n;k++){
- for(i=con[k],p=e[k];p!=NULL;p=p->next){
- for(j=con[p->j],q=ce[i];q!=NULL;q=q->next)
- if(q->j == j) break;
- if(q==NULL&&i!=j) addEdge(ce,i,j);
- }
- }
- return m;
- }
- /*****************************************/
- int main()
- {
- int i,j,k;
- int n,m,con[N],dout[N],din[N];
- Node *e[N],*ce[N],*p;
- int ansA,ansB;
- while(scanf("%d",&n)!=EOF){
- //init
- memp=0;
- clr(e);
- //input
- for(i=0;i<n;i++){
- while(scanf("%d",&j),j)
- addEdge(e,i,j-1);
- }
- //ShrinkConnection
- m=ShrinkConnection(e,n,ce,con);
- //work d[] - ce
- clr(din); clr(dout);
- for(i=0;i<m;i++){
- for(p=ce[i];p!=NULL;p=p->next)
- din[p->j]++,dout[i]++;
- }
- //get ans
- ansA=ansB=0;
- for(i=0;i<m;i++){
- if(din[i]==0) ansA++;
- if(dout[i]==0) ansB++;
- }
- ansB = MAX(ansA,ansB);
- if(m==1) ansB=0;
- printf("%d/n%d/n",ansA,ansB);
- }
- return 0;
- }
- PKU 1236 Network of Schools - 最小点基
- [缩点] poj 1236 Network of Schools
- POJ 1236 Network of Schools tarjan强连通缩点
- POJ 1236 Network of Schools 强联通分量 + 缩点
- poj 1236 Network of Schools 强连通缩点
- POJ 1236 Network of Schools强连通分量缩点
- POJ 1236 Network of Schools (强连通分量+缩点)
- POJ 1236 Network of Schools 强连通分量+缩点
- poj 1236 Network of Schools (强连通分量+缩点)
- POJ 1236 Network of Schools (缩点)
- POJ-1236 Network of Schools 强连通+缩点
- poj 1236 Network of Schools(强连通分量+缩点)
- poj 1236 Network of Schools (强连通分支缩点)
- poj 1236 Network of Schools(强连通缩点)
- Network of Schools - POJ 1236 Tarjan 缩点
- poj 1236 Network of Schools (强联通分量+缩点)
- POJ 1236 Network of Schools(Targan缩点)
- poj 1236 Network of Schools(强连通分量缩点)
- PSRAM
- windows mobile developer 签名
- S3C2410 SDRAM 寄存器设置关键——转载
- 安装sql server 2000 出现sqllog错误解决办法
- php install guide (old version)
- PKU 1236 Network of Schools - 最小点基
- Linux人才成长3部曲
- 基础命令集,忘了那个写那个
- JUnit 教程
- 开源BI系统的简述
- Spring中获得bean的方法
- VC++下剖析黑客软件隐蔽程序的手段
- 虚函数的作用
- Sqlite学习(三) sqlite操作入门(高级语言操作)