题意:给你一个图,可以选定任意的起点st(st入度可以不为0)。从u到达v后,u会被删除。u能够到达v 当且仅当 v的入度为1(到达v后 v的入度为0),求最多可以到达多少个点。
分析:在一个环中的都不一定能全取,缩点不行。考虑tarjan求出拓扑序后枚举起点。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
// #define int __int128
#define pii pair<int,int>
#define endl '\n'//交互题需要endl刷新//
const int maxn=1e6+5;
vector<int>e[maxn];
int x[maxn],y[maxn];
int dfn[maxn],low[maxn],s[maxn],instk[maxn],tp;
int scc[maxn],sc;//节点i所在的scc编号
int sz[maxn];//scc大小
int dfncnt;
int ind[maxn];
int vis[maxn];
int ct;
vector<int>ord;
void tarjan(int u)
{
low[u]=dfn[u]=++dfncnt,s[++tp]=u,instk[u]=1;
for(auto v:e[u])
{
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(instk[v])
{
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u])
{
++sc;
while(1)
{
scc[s[tp]]=sc;
sz[sc]++;
ord.push_back(s[tp]);//记录不缩点的反向拓扑序
instk[s[tp]]=0;
--tp;
if(s[tp+1]==u) break;
}
}
}
void solve()
{
int n;
cin>>n;
for(int i=1;i<=n;i++) e[i].clear(),sz[i]=dfn[i]=ind[i]=vis[i]=0;
dfncnt=sc=tp=0;
ord.clear();
for(int i=1;i<=n;i++)
{
int k;
cin>>k;
for(int j=1;j<=k;j++)
{
int x;
cin>>x;
e[x].push_back(i);
ind[i]++;
}
}
for(int i=1;i<=n;i++)
{
if(!dfn[i]) tarjan(i);
}
reverse(ord.begin(),ord.end());//翻转完是不缩点的拓扑序
int maxx=0;
for(auto st:ord)//枚举起点
{
if(vis[st]) continue;
vector<int>q{st},ops;
for(int i=0;i<q.size();i++)//每次重新计算q.size(),与auto不同
{
int u=q[i];
vis[u]=1;
for(auto v:e[u])
{
if(v==st) continue;//环
ops.push_back(v);
if(--ind[v]==0) q.push_back(v);
}
}
maxx=max(maxx,(int)q.size());//从st出发,最多有q.size()个点入度为0(算上st)
for(auto v:ops) ind[v]++;
}
printf("Case #%lld: %lld\n",++ct,maxx);
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t=1;
cin>>t;
while(t--) solve();
}