这道题很神奇,尤其是背景最神奇,国王竟然能有2000个儿子。
首先,看完题后第一感觉跟二分匹配有关系,结果最后给了一组完美匹配,于是,如果男的喜欢女的就连一条单向边过去,最后那组表示结婚的,就让女的连一条单向边给她丈夫,然后我们观察这个图,如果一个女的能跟这个男的结婚,首先男的必须喜欢她,然后通过这条边过去,到女的结点,然后从女的结点出发,必然能回到这个男的结点处,而且,如果这个女的不是这个男的妻子,那么她必然是从某男结点,然后到达这个男的妻子的结点,然后回到这个男的结点,这就表明,这个男的可以选择另外一个女的做妻子而不会导致某个男的没有妻子选。
那么,这就形成了一个环,而且是男女结点交替,就转化为了强连通分量的求解。
在一个男的喜欢的所有女的中,如果女的跟他是同一个强连通分量,就表示符合要求
另外 这题的输入输出量非常大,我用Kosaraju算法,不加输入输出外挂的话用了10S,加完之后直接就600ms了,直接进第一版
貌似tarjan更快
/* ID: sdj22251 PROG: subset LANG: C++ */ #include <iostream> #include <vector> #include <list> #include <map> #include <set> #include <deque> #include <queue> #include <stack> #include <bitset> #include <algorithm> #include <functional> #include <numeric> #include <utility> #include <sstream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstdlib> #include <cctype> #include <string> #include <cstring> #include <cmath> #include <ctime> #define LOCA #define MAXN 4005 #define INF 100000000 #define eps 1e-7 using namespace std; struct Edge { int v, next; }edge[100 * MAXN], revedge[100 * MAXN]; int head[MAXN], revhead[MAXN], e, visited[MAXN]; int order[MAXN], cnt, id[MAXN]; int n, m; void init() { e = 0; memset(head, -1, sizeof(head)); memset(revhead, -1, sizeof(revhead)); } void insert(const int &x, const int &y) { edge[e].v = y; edge[e].next = head[x]; head[x] = e; revedge[e].v = x; revedge[e].next = revhead[y]; revhead[y] = e; e++; } int in() { char ch; int a = 0; while((ch = getchar()) == ' ' || ch == '\n'); a += ch - '0'; while((ch = getchar()) != ' ' && ch != '\n') { a *= 10; a += ch - '0'; } return a; } void out(int a) { if(a >= 10)out(a / 10); putchar(a % 10 + '0'); } void readdata() { int t, v; for(int i = 1; i <= n; i++) { t = in(); while(t--) { v = in(); insert(i, v + n); } } for(int i = 1; i <= n; i++) { v= in(); insert(v + n, i); } } void dfs(int u) { visited[u] = 1; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].v; if(!visited[v]) dfs(v); } order[cnt++] = u; } void dfs_rev(int u) { visited[u] = 1; id[u] = cnt; for(int i = revhead[u]; i != -1; i = revedge[i].next) { int v = revedge[i].v; if(!visited[v]) dfs_rev(v); } } void Kosaraju() { init(); readdata(); memset(visited, 0, sizeof(visited)); cnt = 0; for(int i = 1; i <= 2 * n; i++) { if(!visited[i]) dfs(i); } memset(visited, 0, sizeof(visited)); cnt = 0; for(int i = 2 * n - 1; i >= 0; i--) { if(!visited[order[i]]) { cnt++; dfs_rev(order[i]); } } for(int u = 1; u <= n; u++) { cnt = 0; int ans[MAXN]; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].v; if(id[u] == id[v]) { ans[cnt++] = v - n; } } sort(ans, ans + cnt); out(cnt); for(int i = 0; i < cnt; i++) { putchar(' '); out(ans[i]); } puts(""); } } int main() { while(scanf("%d", &n) != EOF) { Kosaraju(); } return 0; }
然后写了个非递归的tarjan 应该更快一点吧
#include <iostream> #include <algorithm> #include <cstdio> #include <string> #include <cstring> #include <cmath> #define MAXN 4005 #define INF 100000000 #define eps 1e-7 using namespace std; struct Edge { int v, next; }edge[100 * MAXN]; int head[MAXN], e; int cnt, id[MAXN]; int top, scc, index, top2; int low[MAXN], dfn[MAXN], instack[MAXN]; int st[MAXN], st2[MAXN]; int n, m; void init() { top = scc = index = e = top2 = 0; memset(head, -1, sizeof(head)); memset(dfn, 0, sizeof(dfn)); memset(instack, 0, sizeof(instack)); } void insert(const int &x, const int &y) { edge[e].v = y; edge[e].next = head[x]; head[x] = e++; } int in() { char ch; int a = 0; while((ch = getchar()) == ' ' || ch == '\n'); a += ch - '0'; while((ch = getchar()) != ' ' && ch != '\n') { a *= 10; a += ch - '0'; } return a; } void out(int a) { if(a >= 10)out(a / 10); putchar(a % 10 + '0'); } void readdata() { int t, v; for(int i = 1; i <= n; i++) { t = in(); while(t--) { v = in(); insert(i, v + n); } } for(int i = 1; i <= n; i++) { v= in(); insert(v + n, i); } } void tarjan(int x) { top = 0; st[++top] = x; while(top) { int u = st[top]; if(!dfn[u]) { low[u] = dfn[u] = ++index; instack[u] = 1; st2[++top2] = u; } int v, i; for(i = head[u]; i != -1; i = edge[i].next) { v = edge[i].v; if(!dfn[v]) break; else if(instack[v]) low[u] = min(low[u], dfn[v]); } if(i == -1 && top > 1) low[st[top - 1]] = min(low[u], low[st[top - 1]]); if(i == -1) { if(dfn[u] == low[u]) { scc++; do { v = st2[top2--]; instack[v] = 0; id[v] = scc; } while(v != u); } top--; } else st[++top] = edge[i].v; } } void gao() { init(); readdata(); for(int i = 1; i <= 2 * n; i++) { if(!dfn[i]) tarjan(i); } for(int u = 1; u <= n; u++) { cnt = 0; int ans[MAXN]; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].v; if(id[u] == id[v]) { ans[cnt++] = v - n; } } sort(ans, ans + cnt); out(cnt); for(int i = 0; i < cnt; i++) { putchar(' '); out(ans[i]); } puts(""); } } int main() { while(scanf("%d", &n) != EOF) { gao(); } return 0; }