Files
python/TangDou/AcWing/DCC/POJ1904.cpp
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

98 lines
3.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <iostream>
#include <algorithm>
#include <cstring>
#include <stack>
#include <cstdio>
#include <vector>
using namespace std;
const int N = 4010, M = N * N; // 这个M太BT了!黄海就WA到这里!我一直尝试 M= N<<1, M = N<<2,结果一直错错错!
int n, m; // n个王子,n个姑娘,每个王子喜欢m个姑娘
// 链式前向星
int e[M], h[N], idx, w[M], ne[M];
void add(int a, int b, int c = 0) {
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
// tarjan算法求强连通分量
int stk[N], top; // tarjan算法需要用到的堆栈
bool in_stk[N]; // 是否在栈内
int dfn[N]; // dfs遍历到u的时间
int low[N]; // 从u开始走所能遍历到的最小时间戳
int ts; // 时间戳,dfs序的标识,记录谁先谁后
int id[N], scc_cnt; // 强连通分量块的最新索引号
int sz[N]; // sz[i]表示编号为i的强连通分量中原来点的个数
void tarjan(int u) {
dfn[u] = low[u] = ++ts;
stk[++top] = u;
in_stk[u] = 1;
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (!dfn[j]) {
tarjan(j);
low[u] = min(low[u], low[j]);
} else if (in_stk[j])
low[u] = min(low[u], dfn[j]);
}
if (dfn[u] == low[u]) {
++scc_cnt; // 强连通分量的序号
int x; // 临时变量x,用于枚举栈中当前强连通分量中每个节点
do {
x = stk[top--]; // 弹出节点
in_stk[x] = false; // 标识不在栈中了
id[x] = scc_cnt; // 记录每个节点在哪个强连通分量中
sz[scc_cnt]++; // 这个强连通分量中节点的个数+1
} while (x != u);
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("POJ1904.in", "r", stdin);
#endif
while (~scanf("%d", &n)) { // n个王子,n个姑娘
memset(h, -1, sizeof h); // 初始化链式前向星
memset(dfn, 0, sizeof dfn);
memset(low, 0, sizeof low);
memset(id, 0, sizeof id);
memset(in_stk, 0, sizeof in_stk);
memset(stk, 0, sizeof stk);
memset(sz, 0, sizeof sz);
idx = top = scc_cnt = ts = 0;
for (int i = 1; i <= n; i++) {
scanf("%d", &m); // i号王子喜欢几个姑娘
for (int j = 1; j <= m; j++) { // 是哪几位姑娘
int x;
scanf("%d", &x);
add(i, x + n); // 从王子向妹子连边,建图技巧:(1,n),(n+1,2n)
}
}
for (int i = 1; i <= n; i++) {
int x;
scanf("%d", &x);
add(x + n, i); // 从妹子向王子连边
}
// 注意:图中的点是2*n了,每个王子、姑娘都要占一个点
for (int i = 1; i <= 2 * n; i++)
if (!dfn[i]) tarjan(i); // 跑tarjan
for (int u = 1; u <= n; u++) { // 枚举王子
vector<int> ans;
for (int i = h[u]; ~i; i = ne[i]) { // 枚举王子喜欢的妹子
int v = e[i];
if (id[u] == id[v]) ans.push_back(v - n); // 判断王子和妹子是否在同一强连通分量中
}
printf("%d ", ans.size()); // 这里一定要注意使用%d,黄海写成%lld一直WA到哭
sort(ans.begin(), ans.end()); // 要求按妹子编号升序输出
for (int i = 0; i < ans.size(); i++) printf("%d ", ans[i]); // 每个王子的可匹配妹子数
puts("");
}
}
return 0;
}