Time Limit: 15000MS | Memory Limit: 65536K | |
Total Submissions: 8145 | Accepted: 2955 | |
Case Time Limit: 2000MS |
Description
Input
Output
Sample Input
4 2 1 2 2 1 2 2 2 3 2 3 4 1 2 3 4
Sample Output
2 1 2 2 1 2 1 3 1 4
Hint
This problem has huge input and output data,use scanf() and printf() instead of cin and cout to read data to avoid time limit exceed.
题意:有N个男孩和N个女孩。对每一个男孩,已经给出他所喜欢的女孩。现在给你一个满足完美匹配的婚配表,让你求出另一个表——在满足完美匹配的前提下,每个男孩可以与哪些女孩结婚。
把男孩i虚拟成节点i,女孩i虚拟成节i+N。我们用i - > i+N表示i喜欢i+N,用i+N->i表示 i与i+N结婚。
建图如下:
每个男孩向他喜欢的女孩建边,对于给出的完美匹配婚配表,每个女孩向她的男伴建边。
最后在图中跑一次tarjan。对男孩i所在的SCC,若有一个女孩节点j+N(j女孩)满足i -> j+N 则必然有i可以与j+N结婚。
AC代码:(注意要用数组标记男孩i和女孩j之间是否有边,若一个个查询会TLE)
#include <cstdio> #include <cstring> #include <queue> #include <stack> #include <vector> #include <algorithm> #define MAXN 5000 #define MAXM 20000000 #define INF 0x3f3f3f3f using namespace std; struct Edge { int from, to, next; }; Edge edge[MAXM]; int head[MAXN], edgenum; int low[MAXN], dfn[MAXN]; int sccno[MAXN], scc_cnt; bool Instack[MAXN]; int dfs_clock; stack<int> S; vector<int> scc[MAXN]; int N; void init() { edgenum = 0; memset(head, -1, sizeof(head)); } void addEdge(int u, int v) { Edge E1 = {u, v, head[u]}; edge[edgenum] = E1; head[u] = edgenum++; } int Map[2001][2001]; void getMap() { init(); int a; int num; memset(Map, 0, sizeof(Map)); for(int i = 1; i <= N; i++) { scanf("%d", &num); while(num--) { scanf("%d", &a); addEdge(i, a+N); Map[i][a] = 1; } } for(int i = 1; i <= N; i++) { scanf("%d", &a); addEdge(a+N, i); } } void tarjan(int u, int fa) { int v; low[u] = dfn[u] = ++dfs_clock; S.push(u); Instack[u] = true; for(int i = head[u]; i != -1; i = edge[i].next) { v = edge[i].to; if(!dfn[v]) { tarjan(v, u); low[u] = min(low[u], low[v]); } else if(Instack[v]) low[u] = min(low[u], dfn[v]); } if(low[u] == dfn[u]) { scc_cnt++; scc[scc_cnt].clear(); for(;;) { v = S.top();S.pop(); sccno[v] = scc_cnt; Instack[v] = false; scc[scc_cnt].push_back(v); if(u == v) break; } } } void find_cut(int l, int r) { memset(low, 0, sizeof(low)); memset(dfn, 0, sizeof(dfn)); memset(Instack, false, sizeof(Instack)); memset(sccno, 0, sizeof(sccno)); dfs_clock = scc_cnt = 0; for(int i = l; i <= r; i++) if(!dfn[i]) tarjan(i, -1); } int rec[MAXN];//记录可婚配的女孩编号 void solve() { find_cut(1, 2*N); for(int i = 1; i <= N; i++) { int u = sccno[i];//男孩所在的SCC int sum = 0;//统计数目 for(int j = 0; j < scc[u].size(); j++) { if(scc[u][j] > N && Map[i][scc[u][j]-N])//在一个强连通分量 且有边相连 rec[sum++] = scc[u][j] - N;//记录编号 } printf("%d", sum); sort(rec, rec+sum); for(int j = 0; j < sum; j++) printf(" %d", rec[j]); printf("\n"); } } int main() { while(scanf("%d", &N) != EOF) { getMap(); solve(); } return 0; }