POJ 1236 Network of Schools(强联通分量)
2015-07-31 09:16
477 查看
Description
n(2< n< 100)各学校之间有单向的网络,每个学校得到一套软件后,可以通过单向网络向周边的学校传输,问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。2,至少需要添加几条传输线路(边),使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件
Input
第一行为学校数量n,之后n行第i行有多个整数表示第i个学校与这些学校有传输线路,每行输入以0结束
Output
输出包括两行,第一行为使得网络内所有的学校都能得到软件时所需最少软件数,第二行为需要添加的最少传输线路数
Sample Input
5
2 4 3 0
4 5 0
0
0
1 0
Sample Output
1
2
Solution
首先用tarjan求强联通分量,缩点后设i点的出度为cnt1[i],入度为cnt2[i],ans1为cnt2[i]==0的个数,ans2为cnt1[i]==0的个数,则第一问答案为ans2,第二问答案为max{ans1,ans2}
注意:当强联通分量只有1个的时候第二问答案为0
Code
n(2< n< 100)各学校之间有单向的网络,每个学校得到一套软件后,可以通过单向网络向周边的学校传输,问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。2,至少需要添加几条传输线路(边),使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件
Input
第一行为学校数量n,之后n行第i行有多个整数表示第i个学校与这些学校有传输线路,每行输入以0结束
Output
输出包括两行,第一行为使得网络内所有的学校都能得到软件时所需最少软件数,第二行为需要添加的最少传输线路数
Sample Input
5
2 4 3 0
4 5 0
0
0
1 0
Sample Output
1
2
Solution
首先用tarjan求强联通分量,缩点后设i点的出度为cnt1[i],入度为cnt2[i],ans1为cnt2[i]==0的个数,ans2为cnt1[i]==0的个数,则第一问答案为ans2,第二问答案为max{ans1,ans2}
注意:当强联通分量只有1个的时候第二问答案为0
Code
#include<cstdio> #include<cstring> #include<iostream> #include<cmath> #include<algorithm> #include<stack> #include<vector> using namespace std; #define maxn 111 vector<int>g[maxn]; stack<int>st; int n,scc,index; int low[maxn],dfn[maxn],instack[maxn],fa[maxn]; void init()//初始化 { scc=index=0; while(!st.empty())st.pop(); for(int i=0;i<maxn;i++)g[i].clear(); memset(dfn,0,sizeof(dfn)); memset(instack,0,sizeof(instack)); memset(low,0,sizeof(low)); } void tarjan(int u)//求强联通分量 { dfn[u]=low[u]=++index; instack[u]=1; st.push(u); int v,size=g[u].size(); for(int i=0;i<size;i++) { v=g[u][i]; if(!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if(instack[v]) low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]) { scc++; do { v=st.top(); st.pop(); fa[v]=scc; instack[v]=0; }while(v!=u); } } int main() { while(scanf("%d",&n)!=EOF) { init();//初始化 for(int i=1;i<=n;i++) { int temp; while(scanf("%d",&temp),temp) g[i].push_back(temp);//建边 } for(int i=1;i<=n;i++)//求强联通分量 if(!dfn[i]) tarjan(i); int cnt1[maxn];//每个缩点的出度 int cnt2[maxn];//每个缩点的入度 memset(cnt1,0,sizeof(cnt1));//初始化 memset(cnt2,0,sizeof(cnt2));//初始化 for(int i=1;i<=n;i++)//枚举每条边统计出入度 for(int j=0;j<g[i].size();j++) { int v=g[i][j]; if(fa[i]!=fa[v]) { cnt1[fa[i]]++; cnt2[fa[v]]++; } } int ans1=0;//出度为0的点数 int ans2=0;//入度为0的点数 for(int i=1;i<=scc;i++) { if(!cnt1[i])ans1++; if(!cnt2[i])ans2++; } printf("%d\n",ans2); if(scc!=1) printf("%d\n",max(ans1,ans2)); else printf("0\n");//当只有一个强联通分量时答案为0 } }
相关文章推荐
- JDBC连接与增删查改的封装
- MyBatis开发实战
- 异常处理
- Android系统中解码器
- IOS 真机测试 Xcode出现"The identity used to sign the executable is no longer valid"
- nyoj 79拦截导弹
- DT时代,手机厂商更在意大数据,京东能满足么?
- Copy On Write(写时复制)
- C# 装箱与拆箱
- Python 实用命令
- [MySQL FAQ]系列 — 怎么计算打开文件数
- UI设计:如何设计移动应用的导航
- 关于隐性intent的一些疑惑与解释
- CSS权重
- 基于jQuery扁平多颜色选项卡切换代码
- 开发框架 dhroid源码
- HDU 1021 Fibonacci Again
- SQL注入的方法和解决方案
- [原创]DevOps 的技术栈和工具
- 【转】Windows Server 2008修改远程桌面连接数