poj 1904 强连通分量
思路:先有每个儿子向所有他喜欢的姑娘建边,对于最后给出的正确匹配,我们建由姑娘到相应王子的边。和某个王子在同一强连通分量,且王子喜欢的姑娘都是该王子能娶得。思想类似匈牙利算法求匹配的时候,总能找到增广路径。
代码比较烂,跑了近6s。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<vector> #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) #define Maxn 4010 #define Maxm 400010 using namespace std; int dfn[Maxn],low[Maxn],vi[Maxn],Stack[Maxn],head[Maxn],id[Maxn],n,e,lab,num,top,ans[Maxn],match[2010][2010]; struct Edge{ int u,v,next; }edge[Maxm]; vector<int> q[Maxn]; void init() { memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(vi,0,sizeof(vi)); memset(head,-1,sizeof(head)); memset(id,0,sizeof(id)); memset(match,0,sizeof(match)); for(int i=0;i<Maxn;i++) q[i].clear(); e=lab=num=top=0; } void add(int u,int v) { edge[e].u=u,edge[e].v=v,edge[e].next=head[u],head[u]=e++; } int Tarjan(int u) { dfn[u]=low[u]=++lab; vi[u]=1; Stack[top++]=u; int i,j,v; for(i=head[u];i!=-1;i=edge[i].next) { v=edge[i].v; if(!dfn[v]) { Tarjan(v); low[u]=min(low[u],low[v]); } if(vi[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]) { ++num; do{ i=Stack[--top]; vi[i]=0; id[i]=num; }while(i!=u); } return 0; } void solve() { int i,j; for(i=1;i<=2*n;i++) if(!dfn[i]) Tarjan(i); for(i=n+1;i<=n+n;i++) { q[id[i]].push_back(i-n); } int cnt=0; for(i=1;i<=n;i++) { int size=q[id[i]].size(); cnt=0; for(j=0;j<size;j++) { if(match[i][q[id[i]][j]]) ans[cnt++]=q[id[i]][j]; } printf("%d",cnt); for(j=0;j<cnt;j++) printf(" %d",ans[j]); printf("\n"); } } int main() { int a,b,i,j; while(scanf("%d",&n)!=EOF) { init(); for(i=1;i<=n;i++) { scanf("%d",&a); while(a--) { scanf("%d",&b); add(i,b+n); match[i][b]=1; } } for(i=1;i<=n;i++) { scanf("%d",&a); add(a+n,i); } solve(); } return 0; }