题目链接

Tarjan

题意:每一个王子都有几个喜欢的女孩,国王要你输出一张列表,无论王子选列表中的哪个女孩,其他王子也总能选到其他自己喜欢的女孩。

建图:
这种建图方式其实是自己瞎画的,逻辑解释的通就用了。
一开始给出的原始列表,每个王子就只有一个可选的女孩,这里我们要做的就是把王子和对应的女孩看成一个整体,如果王子不选当下的女孩,那么就和其他自己喜欢的女孩连一条单向边,
假设王子选了其他女孩,那么自己当下的这个女孩就会空出来,所以我的假设是,如果存在 1 -> 2 - > 3 -> 1 这种情况,那么被抛弃的女孩总会有其他王子要,那么圈内的女孩,只要是王子喜欢的
都是可以选的,被选的女孩对应的王子因为女孩被其他王子占了,但是又可以去选圈内的其他女孩,这样圈内的女孩总会有自己的归宿。(我是这么假设的)

注意要排序

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

const int MaxnN = 2000+10;
const int MaxnE = 2e5+10;

struct Edge {
	int v, next;
} edge[MaxnE];

int h[MaxnN], edge_cnt, Hash[MaxnN];
int dfn[MaxnN], low[MaxnN], num[MaxnN];
int indx, Stack[MaxnN], Top, scc;
vector <int> lt[MaxnN];

void add(int u, int v) {
	edge[edge_cnt].v = v;
	edge[edge_cnt].next = h[u];
	h[u] = edge_cnt++;
}

void Tarjan(int u) {
	dfn[u] = low[u] = ++indx;
	Stack[Top++] = u;
	
	for(int i = h[u]; i != -1; i = edge[i].next) {
		Edge e = edge[i];
		if(!dfn[e.v]) {
			Tarjan(e.v);
			low[u] = min(low[u], low[e.v]);
		} else if(!num[e.v]) low[u] = min(low[u], dfn[e.v]);
	}
	if(low[u] == dfn[u]) {
		int v;
		scc++;
		do {
			v = Stack[--Top];
			num[v] = scc;
		} while(u != v);
	}
}

int main(void)
{
	int n;
	while(scanf("%d", &n) != EOF) {
		for(int i = 1; i <= n; ++i) {
			lt[i].clear(); h[i] = -1; 
		}
		edge_cnt = 0;
		int m, tmp;
		for(int i = 1; i <= n; ++i) {
			scanf("%d", &m);
			for(int j = 0; j < m; ++j) {
				scanf("%d", &tmp);
				lt[i].push_back(tmp);
			}
		}
		for(int i = 1; i <= n; ++i) scanf("%d", &Hash[i]);
		int u, v, len;
		for(int i = 1; i <= n; ++i) {
			len = lt[i].size();
			u = Hash[i];
			for(int j = 0; j < len; ++j) {
				v = lt[i][j];
				if(v == u) continue;
				add(u, v);
			}
		}
		for(int i = 1; i <= n; ++i) {
			low[i] = dfn[i] = num[i] = 0;
		}
		indx = Top = scc = 0;
		for(int i = 1; i <= n; ++i) {
			if(!dfn[i]) Tarjan(i);
		}
		
		int cnt;
		for(int i = 1; i <= n; ++i) {
			len = lt[i].size();
			cnt = 0; tmp = num[Hash[i]];
			sort(lt[i].begin(), lt[i].end());
			for(int j = 0; j < len; ++j) if(num[lt[i][j]] == tmp) cnt++;
			printf("%d ", cnt);
			for(int j = 0; j < len; ++j) if(num[lt[i][j]] == tmp) {
				printf("%d", lt[i][j]);
				if(j < len-1) printf(" "); 
			}
			puts("");
		}
		printf("\n");
	}
	return 0;
}