HDU 4685 Prince and Princess
强连通分量,看大神的题解才会写的....
http://www.cnblogs.com/kuangbin/p/3261157.html
数据量有点大,第一次Submit 2995ms过的,时限3000ms,差一点就TLE了。
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> using namespace std; const int maxn = 2000 + 10; int N, M; vector<int>Cun[maxn]; vector<int>G[maxn]; vector<int>FG[maxn]; int nx, ny, Time, Block; int g[maxn][maxn]; int cx[maxn], cy[maxn]; int mk[maxn]; int flag[maxn], dfn[maxn], Belong[maxn]; struct Point { int id, dfn; } point[maxn]; int Scan() { int res = 0, ch, flag = 0; if ((ch = getchar()) == '-') //判断正负 flag = 1; else if (ch >= '0' && ch <= '9') //得到完整的数 res = ch - '0'; while ((ch = getchar()) >= '0' && ch <= '9') res = res * 10 + ch - '0'; return flag ? -res : res; } bool cmp(const Point&a, const Point&b) { return a.dfn>b.dfn; } int path(int u) { for (int v = 1; v <= ny; v++) { if (g[u][v] && !mk[v]) { mk[v] = 1; if (cy[v] == -1 || path(cy[v])) { cx[u] = v; cy[v] = u; return 1; } } } return 0; } int MaxMatch() { int res = 0; memset(cx, -1, sizeof(cx)); memset(cy, -1, sizeof(cy)); for (int i = 1; i <= nx; i++) { if (cx[i] == -1) { memset(mk, 0, sizeof(mk)); res = res + path(i); } } return res; } void dfs(int now) { flag[now] = 1; for (int i = 0; i<G[now].size(); i++) if (!flag[G[now][i]]) dfs(G[now][i]); Time++; dfn[now] = Time; } void Dfs(int now) { Belong[now] = Block; for (int i = 0; i<FG[now].size(); i++) if (!Belong[FG[now][i]]) Dfs(FG[now][i]); } int main() { int CA; CA = Scan(); for (int er = 1; er <= CA; er++){ N = Scan(); M = Scan(); memset(flag, 0, sizeof(flag)); memset(dfn, 0, sizeof(dfn)); memset(Belong, 0, sizeof(Belong)); Time = 0, Block = 0; for (int i = 0; i<maxn; i++) G[i].clear(); for (int i = 0; i<maxn; i++) Cun[i].clear(); for (int i = 0; i<maxn; i++) FG[i].clear(); memset(g, 0, sizeof(g)); nx = N, ny = M; for (int i = 1; i <= N; i++) { int ToT, To; ToT = Scan(); while (ToT--) { To = Scan(); Cun[i].push_back(To); g[i][To] = 1; } sort(Cun[i].begin(), Cun[i].end()); } int res = MaxMatch(); memset(g, 0, sizeof(g)); int A = M - res, B = N - res;//A表示虚拟王子数量,B表示虚拟妹子数量 nx = N + A, ny = M + B; if (B>0)//王子有单身 { for (int j = M + 1; j <= M + B; j++) for (int i = 1; i <= N; i++) { g[i][j] = 1; G[i].push_back(j + nx); FG[j + nx].push_back(i); } } if (A>0) { for (int i = N + 1; i <= N + A; i++) for (int j = 1; j <= M; j++) { g[i][j] = 1; G[i].push_back(j + nx); FG[j + nx].push_back(i); } } for (int i = 1; i <= N; i++) for (int j = 0; j<Cun[i].size(); j++) { g[i][Cun[i][j]] = 1; G[i].push_back(Cun[i][j] + nx); FG[Cun[i][j] + nx].push_back(i); } MaxMatch(); for (int i = 1; i <= ny; i++) if (cy[i] != -1) { G[i + nx].push_back(cy[i]); FG[cy[i]].push_back(i + nx); } for (int i = 1; i <= nx + ny; i++) if (!dfn[i]) dfs(i); for (int i = 0; i<nx + ny; i++) point[i].id = i + 1, point[i].dfn = dfn[i + 1]; sort(point, point + nx + ny, cmp); for (int i = 0; i<nx + ny; i++) if (!Belong[point[i].id]) Block++, Dfs(point[i].id); int RT; int ans[maxn]; printf("Case #%d:\n", er); for (int i = 1; i <= N; i++) { RT = 0; for (int j = 0; j<Cun[i].size(); j++) { if (Belong[i] == Belong[Cun[i][j] + nx]) { ans[RT] = Cun[i][j]; RT++; } } printf("%d", RT); for (int x = 0; x<RT; x++) printf(" %d", ans[x]); printf("\n"); } } return 0; }