题解:
二分图匹配
对于每一个单身狗
见一个虚拟的人
然后就可以做了
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=2000; const int M=1000000+3000; struct EDGE{int v,next;}edge[M]; int first[N],low[N],dfn[N],sta[M],belong[N]; int ans[N],match[N],flag[N]; bool instack[N],vis[N]; int n,m,g,cnt,top,scc,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; } void Out(int a) { if (a>9) Out(a/10); putchar(a%10+'0'); } void AddEdge(int u,int v) { edge[g].v=v; edge[g].next=first[u]; first[u]=g++; } int min(int a,int b) { return a<b?a:b; } int max(int a,int b) { return a>b?a:b; } void init() { g=cnt=top=scc=0; memset(first,-1,sizeof(first)); memset(dfn,0,sizeof(dfn)); memset(instack,0,sizeof(instack)); memset(flag,0,sizeof(flag)); n=Scan(); m=Scan(); maxn=max(n,m); } bool dfs(int u) { int i,v; for (i=first[u];i!=-1;i=edge[i].next) { v=edge[i].v; if (!vis[v]) { vis[v]=1; if (match[v]==0||dfs(match[v])) { match[v]=u; flag[u]=v; return 1; } } } return 0; } void xiong() { int i; memset(match,0,sizeof(match)); for (i=1;i<=maxn;i++) { memset(vis,0,sizeof(vis)); dfs(i); } } void Tarjan(int u) { low[u]=dfn[u]=++cnt; sta[++top]=u; instack[u]=1; for (int i=first[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if (!dfn[v]) { Tarjan(v); low[u]=min(low[u],low[v]); } else if (instack[v])low[u]=min(low[u],dfn[v]); } if (low[u]==dfn[u]) { scc++; while (1) { int v=sta[top--]; instack[v]=0; belong[v]=scc; if (u==v) break; } } } void build() { int i,k,v,j; for (i=1;i<=n;i++) { k=Scan(); while(k--) { v=Scan(); AddEdge(i,v+maxn); } } xiong(); int all=2*maxn; for (i=1;i<=maxn;i++) { if (!flag[i]) { all++; for (j=1;j<=maxn;j++) AddEdge(j,all); match[all]=i; flag[i]=all; } } for (i=maxn+1;i<=2*maxn;i++) { if (!match[i]) { all++; for (j=maxn+1;j<=2*maxn;j++) AddEdge(all,j); flag[all]=i; match[i]=all; } } for (i=1;i<=all;i++) if (flag[i])AddEdge(flag[i],i); } void solve() { int i,u,v; for (i=1;i<=maxn;i++) if (!dfn[i])Tarjan(i); for (u=1;u<=n;u++) { int count=0; for (i=first[u];i!=-1;i=edge[i].next) { v=edge[i].v; if (belong[u]==belong[v]) { if (v-maxn>m) continue; ans[count++]=v-maxn; } } sort(ans,ans+count); Out(count); for (i=0;i<count;i++) { putchar(' '); Out(ans[i]); } putchar(' '); } } int main() { int t=Scan(); for (int cas=1;cas<=t;cas++) { init(); build(); printf("Case #%d: ",cas); solve(); } return 0; }