这段时间要沉迷刷题一段时间了,就让CSDN陪我一起吧!
一、题目大意
题目的大致意思是国王有N个儿子,也就是王子,每个王子有Ki个喜欢的姑娘,总共有N个姑娘,巫师给出了一种王子结婚的办法,国王觉得不是很好,要求求出每个王子可以结婚的姑娘有哪些,并且要保证每个王子都可以和自己喜欢的姑娘结婚。
二、题目思路以及AC代码
这道题,我承认,我不会。我还特地去学习了一些Tarjan求强连通分量是怎么写的。
但是看完题解,我就会了。这道题的大致思路就是,首先建图,然后求强连通分量,听起来也不是很难。关于建图,首先如果王子 u 喜欢某个姑娘 v,那么则有一条王子到姑娘的边(u, v),然后由于题目还给了一个巫师的标准答案,所以在标准答案中,如果王子 u 和某个姑娘 v 结婚,那么则有一条姑娘到王子的边(v, u),这样就建完图了,然后求解强连通分量就可以了,与王子在同一个强连通分量的姑娘则可以和王子结婚,且保证其他的王子也都可以和自己喜欢的姑娘结婚。
那是为什么呢?下面我就简单解释一下,因为巫师已经给出了一个正确的答案,那么我们就可以在这个正确答案的基础上进行修改,也就是换一换结婚的对象,只要保证,王子换一下,另一个王子同时可以有姑娘结婚就行了。首先对于给出的答案,相互结婚的王子 u 和姑娘 v 肯定是可以互相可达的,如果此时有另一个姑娘 p 和王子 u 在同一个强连通分量中,同时不要忘了,p 本来肯定是和一个王子结婚的,我们假设巫师给出和 p 结婚的王子为 w ,那么此时,至少 u、v、p、w 都是处于同一个强连通分量的,所以王子和这里的任意一个姑娘结婚,另一个王子都有相应的姑娘去结婚,也就是我们需要的结果。
这里要提醒一下,在实现的时候,千万不要把MAXN开成 2010,虽然N最大的2000,但建图的时候有最多2000个王子,2000个姑娘,所以要把MAXN开至少4010,不要学我…
下面给出AC代码:
#pragma warning(disable: 4996)
#include <iostream>
#include <vector>
#include <stack>
#include <algorithm>
#include <queue>
#include <functional>
#define MAXN 4010
using namespace std;
int n;
vector<int> edges[MAXN];
int k[MAXN];
// Tarjan
int dfn[MAXN], low[MAXN], vis[MAXN];
int index = 0;
stack<int> s;
// result
int belong[MAXN];
int scc = 0;
void init() {
while (!s.empty()) s.pop();
for (int i = 0; i < MAXN; i++) {
edges[i].clear();
}
}
void Tarjan(int u) {
dfn[u] = low[u] = ++index;
s.push(u);
vis[u] = true;
int size = edges[u].size();
for (int i = 0; i < size; i++) {
int v = edges[u][i];
if (!dfn[v]) {
Tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (vis[v]) {
low[u] = min(low[u], dfn[v]);
}
}
if (low[u] == dfn[u]) {
int v;
scc++;
do {
v = s.top(); s.pop();
vis[v] = false;
belong[v] = scc;
} while (u != v);
}
}
int main() {
init();
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &k[i]);
for (int j = 1; j <= k[i]; j++) {
int v;
scanf("%d", &v);
edges[i].push_back(n + v);
}
}
for (int i = 1; i <= n; i++) {
int u;
scanf("%d", &u);
edges[n + u].push_back(i);
}
for (int i = 1; i <= 2 * n; i++) {
if (!dfn[i])
Tarjan(i);
}
for (int i = 1; i <= n; i++) {
int size = edges[i].size();
int cnt = 0;
priority_queue<int, vector<int>, greater<int>> q;
for (int j = 0; j < size; j++) {
int v = edges[i][j];
if (belong[i] == belong[v]) {
cnt++;
q.push(v);
}
}
printf("%d ", cnt);
while (!q.empty()) {
printf("%d ", q.top() - n);
q.pop();
}
printf("\n");
}
return 0;
}
如果有问题,欢迎大家指正!!!