POJ - 1904 King's Quest (强连通)
题意:有N个王子,每个王子有任意个喜欢的妹子,巫师会给出一个方案:每个妹子都嫁给一个王子。但是国王希望知道:每个王子能在哪些妹子中择偶而不影响其他王子择偶。
分析:设王子为x部,妹子为y部,假设有匹配xi与yi和xj和yj,当xi中意yj且xj中意yi时。那么xi,xj改变对象不会影响最大匹配数。可以将寻找新的伴侣与匈牙利算法中寻找增广路的过程联想在一起。如果在这几对人中能找到一条完整地交错轨,那么就可以对Y部进行任意选择。
所以本题转化为球每个强连通分量中的点。
#include<iostream> #include<stdio.h> #include<cstring> #include<stack> #include<algorithm> #include<vector> using namespace std; typedef long long LL; const int maxn =4e3+5,maxm = 3e5+5; const int INF =0x3f3f3f3f; struct Edge{int to,next;}edges[maxm]; int head[maxn],tot; stack<int> S; int pre[maxn],low[maxn],sccno[maxn],dfn,scc_cnt; int sccnum[maxn]; void init(int N) { tot=dfn=scc_cnt=0; memset(pre,0,sizeof(pre)); memset(sccno,0,sizeof(sccno)); memset(head,-1,sizeof(head)); } void AddEdge(int u,int v) { edges[tot] = (Edge){v,head[u]}; head[u] = tot++; } void Tarjan(int u) { int v; pre[u]=low[u]=++dfn; S.push(u); for(int i=head[u];~i;i=edges[i].next){ v= edges[i].to; if(!pre[v]){ Tarjan(v); low[u]=min(low[u],low[v]); } else if(!sccno[v]){ low[u]=min(low[u],pre[v]); } } if(pre[u]==low[u]){ int x; ++scc_cnt; for(;;){ x = S.top();S.pop(); sccno[x]=scc_cnt; if(x==u)break; } } } 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'); } int res[maxn]; int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); #endif int N,u,v,k,tmp; while(scanf("%d",&N)==1){ init(N*2); for(int i=1;i<=N;++i){ k = Scan(); while(k--){ v = Scan(); AddEdge(i,v+N); } } for(int i=1;i<=N;++i){ u = Scan(); AddEdge(u+N,i); } for(int i=1;i<=2*N;++i){ if(!pre[i]) Tarjan(i); } for(int u=1;u<=N;++u){ int cnt=0; for(int i=head[u];~i;i=edges[i].next){ int v = edges[i].to; if(sccno[u]==sccno[v]){ res[cnt++] = v-N; } } sort(res,res+cnt); Out(cnt); for(int i=0;i<cnt;++i){ putchar(' '); Out(res[i]); } putchar('\n'); } } return 0; }
为了更好的明天