强连通分量,看大神的题解才会写的....
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 = + ;
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 = , ch, flag = ; if ((ch = getchar()) == '-') //判断正负
flag = ; else if (ch >= '' && ch <= '') //得到完整的数
res = ch - '';
while ((ch = getchar()) >= '' && ch <= '')
res = res * + ch - ''; return flag ? -res : res;
} bool cmp(const Point&a, const Point&b)
{
return a.dfn>b.dfn;
} int path(int u)
{
for (int v = ; v <= ny; v++)
{
if (g[u][v] && !mk[v])
{
mk[v] = ;
if (cy[v] == - || path(cy[v]))
{
cx[u] = v;
cy[v] = u;
return ;
}
}
}
return ;
} int MaxMatch()
{
int res = ;
memset(cx, -, sizeof(cx));
memset(cy, -, sizeof(cy));
for (int i = ; i <= nx; i++)
{
if (cx[i] == -)
{
memset(mk, , sizeof(mk));
res = res + path(i);
}
}
return res;
} void dfs(int now)
{
flag[now] = ;
for (int i = ; 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 = ; i<FG[now].size(); i++)
if (!Belong[FG[now][i]])
Dfs(FG[now][i]);
} int main()
{
int CA;
CA = Scan();
for (int er = ; er <= CA; er++){
N = Scan();
M = Scan();
memset(flag, , sizeof(flag));
memset(dfn, , sizeof(dfn));
memset(Belong, , sizeof(Belong));
Time = , Block = ;
for (int i = ; i<maxn; i++) G[i].clear();
for (int i = ; i<maxn; i++) Cun[i].clear();
for (int i = ; i<maxn; i++) FG[i].clear();
memset(g, , sizeof(g));
nx = N, ny = M; for (int i = ; i <= N; i++)
{
int ToT, To;
ToT = Scan();
while (ToT--)
{
To = Scan();
Cun[i].push_back(To);
g[i][To] = ;
}
sort(Cun[i].begin(), Cun[i].end());
}
int res = MaxMatch(); memset(g, , sizeof(g));
int A = M - res, B = N - res;//A表示虚拟王子数量,B表示虚拟妹子数量
nx = N + A, ny = M + B;
if (B>)//王子有单身
{
for (int j = M + ; j <= M + B; j++)
for (int i = ; i <= N; i++)
{
g[i][j] = ;
G[i].push_back(j + nx);
FG[j + nx].push_back(i);
}
}
if (A>)
{
for (int i = N + ; i <= N + A; i++)
for (int j = ; j <= M; j++)
{
g[i][j] = ;
G[i].push_back(j + nx);
FG[j + nx].push_back(i);
}
}
for (int i = ; i <= N; i++)
for (int j = ; j<Cun[i].size(); j++)
{
g[i][Cun[i][j]] = ;
G[i].push_back(Cun[i][j] + nx);
FG[Cun[i][j] + nx].push_back(i);
}
MaxMatch();
for (int i = ; i <= ny; i++)
if (cy[i] != -)
{
G[i + nx].push_back(cy[i]);
FG[cy[i]].push_back(i + nx);
} for (int i = ; i <= nx + ny; i++) if (!dfn[i]) dfs(i);
for (int i = ; i<nx + ny; i++) point[i].id = i + , point[i].dfn = dfn[i + ];
sort(point, point + nx + ny, cmp);
for (int i = ; 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 = ; i <= N; i++)
{
RT = ;
for (int j = ; 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 = ; x<RT; x++) printf(" %d", ans[x]);
printf("\n");
}
}
return ;
}