题干:
商业信息共享
有 N 个公司,从每个公司都能单向地向另外一个公司分享最新商业信息,因为他们之间有着某种合作,你需要解决两个问题:
现在有一个最新的商业信息,至少需要告诉多少个公司,使得所有的公司最终都能得到该信息。
在原有基础上,至少需要再让多少对公司建立这种合作,使任意一个公司获得某个最新商业信息后,经过若干次分享,所有的公司最终都能得到该信息。
输入格式
第一行输入一个整数 N (1≤N≤100)。
接下来 N行,每行若干个整数,表示第 ii 个公司可以向哪些公司分享信息,以 0 结束。
输出格式
输出共两行,每行一个整数,分别表示问题 1 和问题 2 的答案。
样例输入
6
0
6 0
2 0
2 0
3 1 0
0
样例输出
2
2
题目大意:
两个要求,
1.用最少的公司,将所有的信息传递给其他的公司。
2.最少加多少条边,使图变成强联通图。
解题报告:
又是“传递关系”的问题,还是用tarjan缩点做。
对于1小问,其实就是运用性质①,找入度为0的超级点(你自己联想线性序列嘛!其实就是求这里有几坨线性序列)
对于第2小问也是以“超级点”来做的:
需要思考一下,首先你要知道超级点其实就是一个强联通分量(涵盖的点互相可达),那么对于每个超级点,如果既有边指向它,它又可以指出去,如果每个点都这样“开放 既可以get in又可以get out”,那其实就满足题意说的“任意一个点发消息可达所有点”。否则你想想,如果入度为0了,那么这个超级点只能get out,别人访问不了你啊!同理,出度为0,你访问不了别人啊!这两种情况都会不符合题意的。所以我们就需要找到有没有超级点是出/入度为0的,如果你入度为0,那么我需要给你随便连一条边进来好让别人能够get in,如果你出度为0,那么我需要给你随便连一条边出去好让你可以get out。
因为我连一条线可以解决同时解决一个出度为0和一个入度为0的问题,如果只剩出度为0的问题了,就任意给它连出去就好了,因此,max(出度=0的点数,入度=0的点数)即为所求。
AC代码:(没地方交,不知道正确与否)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
const int MAX = 2e5 + 5;
int n,m;y
int head[MAX];
int DFN[MAX],LOW[MAX],col[MAX],cnt[MAX],stk[MAX],out[MAX];
bool vis[MAX];
struct Edge {int fr,to,ne;
} e[MAX],ee[MAX];
int tot,tot2,timing,scc,index;
void add(int u,int v) {e[++tot].fr = u;e[tot].to = v;e[tot].ne = head[u];head[u] = tot;
}
void Tarjan(int x) {LOW[x] = DFN[x] = ++timing;vis[x] = 1;stk[++index] = x;for(int i = head[x]; i!=-1; i=e[i].ne) {int v = e[i].to;if(!DFN[v]) {Tarjan(v);LOW[x] = min(LOW[x],LOW[v]);}else if(vis[v]) LOW[x] = min(LOW[x],DFN[v]);}if(DFN[x] == LOW[x]) {scc++;while(1) {int tmp = stk[index];index--;vis[tmp]=0;col[tmp] = scc;cnt[scc]++;if(x == tmp) break;}}
}
int main()
{cin>>n;memset(head,-1,sizeof head);for(int a,b,i = 1 ; i<=n; i++) {while(scanf("%d",&b) && b) {add(i,b);}}for(int i = 1; i<=n; i++) {if(!DFN[i]) Tarjan(i);}for(int i = 1; i<=m; i++) {if(col[e[i].fr] != col[e[i].to]) {out[col[e[i].fr]]++;in[col[e[i].to]]++;}}int cntin=0,cntout=0;for(int i = 1; i<=scc; i++) {if(out[i] == 0) cntout++;if(in[i] == 0) cntin++;}printf("%d\n",cntin);printf("%d\n",max(cntin,cntout));return 0 ;
}