Network of Schools - tarjan缩点
题目:https://vjudge.net/contest/388498#problem/G
题意:有向图。每个点能把当前信息传达到其指向的点。问题1:至少需要提供给多少个点信息才能让信息传遍所有点;问题2:至少需要补多少条有向边才能,给任意一个点信息能够传遍所有点。
题解:
问题1实际上是问缩点后的图里有多少个入度为0的点。因为非入度为0的点可以从其他点那获得信息,不需要向他提供信息。
问题2实际上是问,缩点后图里入度为0的点数量rd0,出度为0的点的数量cd0。求这两个值的最大值。要实现题目的需求,就是对于任意一点,可以到达所有点。由这个可以推出,任意一点,都可以被其他点到达。等价于,任意一点,其入度和出度都不为0。
新建一条边最佳情况下可以减少一个入度为0的点和一个出度为0的点。所以至少需要max(rd0,cd0)条边。
参考博客:https://blog.csdn.net/weixin_42868863/article/details/102847615
#include <iostream> #include <stdio.h> #include <algorithm> #include <queue> #include <stack> #include <cstring> #include <map> #include <set> #define ALL(x) x.begin(),x.end() using namespace std; typedef long long ll; const ll mx=100+10; ll low[mx], dfn[mx], cnt; ll e[mx][mx]; ll n; void read(){ cnt=0; for(ll i=1;i<mx;i++){ low[i]=dfn[i]=-1; for(ll j=1;j<mx;j++) e[i][j]=-1; } scanf("%lld", &n); for(ll i=1;i<=n;i++){ ll v; while(1){ scanf("%lld", &v); if(v==0) break; e[i][v]=1; } } } ll sum;//统计颜色 ll color[mx]; ll vis[mx];//是否在栈中 stack<ll>s; void tarjan(ll c, ll fa){ dfn[c]=low[c]=++cnt; s.push(c);vis[c]=1; for(ll i=1;i<=n;i++){ if(e[c][i]==-1)continue; if(i==fa || i==c) continue; if(dfn[i]==-1){//没有经过 tarjan(i, c); low[c]=min(low[c], low[i]); } else if(vis[i]==1){//已经经过了 i是父亲 low[c]=min(low[c], dfn[i]);//直接相连的父亲 } } if(low[c]==dfn[c]){//自己和子结点形成了强连通 或者只有自己一个人 color[c]=++sum; vis[c]=0; while(!s.empty() && s.top()!=c){ color[s.top()]=sum; vis[s.top()]=0;//出栈 s.pop(); } s.pop();//把c给pop掉 } } ll rd[mx], cd[mx]; ll e2[mx][mx]; void init(){//把color数组转化为数据 for(ll i=1;i<=n;i++){ for(ll j=1;j<=n;j++){ //i->j if(e[i][j]==-1 || i==j)continue; ll u=color[i], v=color[j]; if(u==v) continue; e2[u][v]=1; } } for(ll i=1;i<=sum;i++){ for(ll j=1;j<=sum;j++){ if(i==j)continue; if(e2[i][j]==0)continue; rd[j]++;cd[i]++; } } ll rd0=0, cd0=0; for(ll i=1;i<=sum;i++){ if(rd[i]==0)rd0++; if(cd[i]==0)cd0++; } if(sum==1){ printf("1\n0\n"); return; } printf("%lld\n%lld\n", rd0, max(rd0, cd0)); } void solve(){ read(); for(ll i=1;i<=n;i++){ if(dfn[i]==-1) tarjan(i, -1); } init(); } int main(){ solve(); return 0; }