一共有 (N) 个科目,其中有 (M) 个主要科目,只要 (M) 个主要科目都通过了,那么对应主人公就可以毕业了,也就是达成了目的。现在有一个列表,表示要通过第 (i) 门课程需要先通过的科目列表。现在主人公希望得到一个通过科目的顺序,使得最终他通过最少的科目使得主人公毕业。
Solution
如果有环,则无解
对于每个主科目,从这个点开始,在反图上 DFS 即可,遇到已经标记的点就退出
输出时按照拓扑序输出
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 100005;
int n,m,t1,t2,t3,s[N],tim[N],fg[N],vis[N],ind;
vector <int> g[N];
namespace scc {
vector <int> scc[N];
int ind,f[N],siz[N],dfn[N],low[N],vis[N],s[N],bel[N],top,tot,m;
void dfs(int p) {
s[++top]=p;
dfn[p]=low[p]=++ind;
for(int i=0;i<g[p].size();i++) {
int q=g[p][i];
if(!dfn[q]) dfs(q), low[p]=min(low[p],low[q]);
else if(!bel[q]) low[p]=min(low[p],dfn[q]);
}
if(dfn[p]==low[p]) {
++tot;
for(int i=0;i!=p;) {
i=s[top--];
bel[i]=tot;
scc[tot].push_back(i);
}
}
}
void solve() {
for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i);
}
}
void dfs(int p) {
vis[p]=1;
for(int q:g[p]) if(vis[q]==0) dfs(q);
tim[p]=++ind;
}
int cmp(int a,int b) {
return tim[a]<tim[b];
}
void mark(int p) {
fg[p]=1;
for(int q:g[p]) if(fg[q]==0) mark(q);
}
signed main() {
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=m;i++) {
cin>>s[i];
}
for(int i=1;i<=n;i++) {
cin>>t1;
while(t1--) {
cin>>t2;
g[i].push_back(t2);
}
}
scc::solve();
int flag=0;
for(int i=1;i<=n;i++) if(!vis[i]) dfs(i);
for(int i=1;i<=m;i++) mark(s[i]);
for(int i=1;i<=n;i++) if(fg[i]&&scc::scc[scc::bel[i]].size()>1)
flag=1;
if(flag) {
cout<<-1;
}
else {
vector <int> ans;
for(int i=1;i<=n;i++) if(fg[i]) ans.push_back(i);
sort(ans.begin(),ans.end(),cmp);
cout<<ans.size()<<endl;
for(int i:ans) cout<<i<<" ";
}
}