诸位先练习一下阅读理解。
分析
一开始我想到的是缩点之后用拓扑去递推就行,一直以为是对的但是调不出来,然后被旁边大佬一组数据hack掉了(非常崩溃崩溃bkbkbkbk找jq呜呜呜)。然后发现拓扑只要对于有“多对一”这样图的都无法计算或者去重,于是放弃2.5h的思路。
在思考拓扑的时候想过记录前驱,那不就变成DFS了吗?于是就打DFS。
DFS之前要反向建边,从入度(反图中)为0的节点开始DFS,因为只有这些点可以作为答案,然后记录每个强连通分量的最终答案(可见答案就是DFS中经过的点数总和),最后让每个点对应上强连通分量就可以了。
官方解释:
其实实现的时候非常多细节,比如两个邻接表的转换,一堆初始化,对于点的下标的+1处理,数组开大点等等。
上代码
又是类似调“疫情控制”的一天。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
struct jq
{
int to,next;
}e[50010],en[50010];
int t,n,m,id;
int hd[50010],tot;
int hdn[50010],totn;
int sum[5010],in[5010],mx,ans[5010],calc,vis[5010];
int dfn[5010],col[5010],low[5010],tmp[5010],timi,cnt;
void add(int x,int y)
{
e[++tot]=(jq){y,hd[x]};
hd[x]=tot;
}
void addn(int x,int y)
{
en[++totn]=(jq){y,hdn[x]};
hdn[x]=totn;
}
stack<int> st;
void tarjan(int x)
{
dfn[x]=low[x]=++timi;
st.push(x);
for(int i=hd[x];i;i=e[i].next)
{
int v=e[i].to;
if(!dfn[v])
{
tarjan(v);
low[x]=min(low[x],low[v]);
}
else if(!col[v]) low[x]=min(low[x],low[v]);
}
if(dfn[x]==low[x])
{
col[x]=++cnt;
sum[cnt]++;
while(st.top()!=x)
{
sum[cnt]++;
col[st.top()]=cnt;
st.pop();
}
st.pop();
}
}
void dfs(int x)
{
vis[x]=1;
calc+=sum[x];
for(int i=hdn[x];i;i=en[i].next)
{
if(vis[en[i].to]) continue;
dfs(en[i].to);
}
}
int main()
{
cin>>t;
while(t--)
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x+1,y+1);
}
for(int i=1;i<=n;i++)
{
if(!dfn[i]) tarjan(i);
}
for(int i=1;i<=n;i++)
{
for(int j=hd[i];j;j=e[j].next)
{
int v=e[j].to;
if(col[i]!=col[v])
{
addn(col[v],col[i]);
in[col[i]]++;
}
}
}
for(int i=1;i<=cnt;i++)
{
if(!in[i])
{
memset(vis,0,sizeof(vis));
calc=0;
dfs(i);
ans[i]=calc-1;
mx=max(mx,ans[i]);
}
}
printf("Case %d: %d\n",++id,mx);
for(int i=1;i<=n;i++)
{
if(ans[col[i]]==mx) cout<<i-1<<' ';
}
cout<<endl;
memset(dfn,0,sizeof(dfn));
memset(col,0,sizeof(col));
memset(sum,0,sizeof(sum));
memset(low,0,sizeof(low));
tot=totn=cnt=mx=timi=0;
memset(hd,0,sizeof(hd));
memset(hdn,0,sizeof(hdn));
memset(in,0,sizeof(in));
memset(e,0,sizeof(e));
memset(en,0,sizeof(en));
memset(ans,0,sizeof(ans));
while(!st.empty()) st.pop();
}
return 0;
}