请你确定x和y
使得x+y=n,同时x个人不认识y只猫
结论1:对于每组人和猫,必选其一
首先,当我们选择一个人的时候,他自己养的猫和认识的猫一定不能选
根据结论1就必须选择他认识的猫的主人,否则会导致人数不够
由于认识关系是单向的,所以是一张有向图
选择一个人之后必须选择它的所有出边
结论2:一整个强连通分量必选
那么先强连通分量缩点,然后形成一个DAG,在DAG上找一个出度为0的点作为x,剩下的作为y即可
#include<bits/stdc++.h> using namespace std; const int maxn=1e6+100; int n,m,t; vector<int> g[maxn]; int low[maxn],dfn[maxn],cnt,scc,pos[maxn]; stack<int> st; void tj (int x) { low[x]=dfn[x]=++cnt; st.push(x); for (int y:g[x]) { if (!low[y]) { tj(y); low[x]=min(low[x],low[y]); } else if (!pos[y]) { low[x]=min(low[x],dfn[y]); } } if (low[x]==dfn[x]) { scc++; while (1) { int u=st.top(); st.pop(); low[u]=low[x]; pos[u]=scc; if (u==x) break; } } } int in[maxn],out[maxn]; int x[maxn],y[maxn]; int main () { scanf("%d",&t); while (t--) { scanf("%d%d",&n,&m); cnt=scc=0; while (st.size()) st.pop(); for (int i=1;i<=n;i++) pos[i]=dfn[i]=low[i]=out[i]=0; for (int i=1;i<=n;i++) g[i].clear(); for (int i=1;i<=m;i++) { scanf("%d%d",x+i,y+i); if (x[i]==y[i]) continue; g[x[i]].push_back(y[i]); } for (int i=1;i<=n;i++) if (!low[i]) tj(i); for (int i=1;i<=m;i++) if (pos[x[i]]!=pos[y[i]]) out[pos[x[i]]]++; if (scc==1) { printf("No "); continue; } for (int i=1;i<=scc;i++) { if (out[i]==0) { int cnt=0; for (int j=1;j<=n;j++) cnt+=(pos[j]==i); printf("Yes %d %d ",cnt,n-cnt); for (int j=1;j<=n;j++) if (pos[j]==i) printf("%d ",j); printf(" "); for (int j=1;j<=n;j++) if (pos[j]!=i) printf("%d ",j); printf(" "); break; } } } }