题意:1e6个人每人有一只猫 每个人认识自己的猫 现给出一些关系表示一个人认识某只猫
要选出一些人和一些猫 使得每个人都不认识选出来的猫 且人+猫=n
题解:答案肯定是 一个人的集合和一个猫的集合
那么对于某个人 他要么在这个答案集合中 要么不在 我们考虑第一个人
先考虑这个人在答案集合中 如果这个人认识某只猫 那么拥有这只猫的主人显然也应该放在答案集合中
所以不停把人放入队列进来 如果最后这个人的集合没有n个人 则是一种合法的方案
然后考虑第一个人不在答案集合中 那么逆向思维等于我们选了第一个人的猫 如果某个人认识这只猫
那么这个人的猫也应该放在猫的集合里 瞎搞搞就完了
#include <bits/stdc++.h> using namespace std; int n, m, l, r; vector<int> g[2][1000005]; int que[1000005]; int vis[1000005]; void solve(int typ) { for(int i = 1; i <= n; i++) vis[i] = 0; l = 1, r = 0; que[++r] = 1; vis[1] = 1; while(l <= r) { int u = que[l]; l++; for(int i = 0; i < g[typ][u].size(); i++) { int v = g[typ][u][i]; if(!vis[v]) { vis[v] = 1; que[++r] = v; } } } } int main() { int T; scanf("%d", &T); while(T--) { scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) g[0][i].clear(), g[1][i].clear(); for(int i = 1; i <= m; i++) { int x, y; scanf("%d%d", &x, &y); if(x == y) continue; g[0][x].push_back(y); g[1][y].push_back(x); } solve(0); if(r != n) { puts("Yes"); printf("%d %d ", r, n - r); for(int i = 1; i <= r; i++) printf("%d ", que[i]); puts(""); for(int i = 1; i <= n; i++) if(!vis[i]) printf("%d ", i); puts(""); continue; } solve(1); if(r != n) { puts("Yes"); printf("%d %d ", n - r, r); for(int i = 1; i <= n; i++) if(!vis[i]) printf("%d ", i); puts(""); for(int i = 1; i <= r; i++) printf("%d ", que[i]); puts(""); continue; } puts("No"); } return 0; }