King's Quest

时间:2022-09-11 08:36:08

poj1904:http://poj.org/problem?id=1904

题意:国王有n个儿子,现在这n个儿子要在n个女孩里选择自己喜欢的,有的儿子可能喜欢多个,最后国王的向导给出他一个匹配,匹配有n个数,代表某个儿子和哪个女孩可以结婚,已知这些条件,要你找出每个儿子可以和哪些女孩结婚

题解:首先儿子和喜欢女孩建一条边,然后最后的女孩和儿子建一条边,然后缩点就可以了,至于为什么这么做,还在研究当中。

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
vector<int>ans;
const int N=+;
const int M=;
const int INF=0xffffffff;
struct Edge{
int to,next;
} edge[M];
int n,m,temp,cnt,dep,top,atype;
int dfn[N],low[N],vis[N],head[N],st[N],belong[N],in[N],out[N],sum[N];
//sum[i]记录第i个连通图的点的个数,in[i],out[i],表示缩点之后点的入度和初度。
void init(){
cnt=dep=top=atype=;
memset(head,-,sizeof(head));
memset(dfn,,sizeof(dfn));
memset(low,,sizeof(low));
memset(vis,,sizeof(vis));
memset(belong,,sizeof(belong));
memset(in,,sizeof(in));
memset(out,,sizeof(out));
memset(sum,,sizeof(sum));
}
void addedge(int u,int v){
edge[cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt++;
} void Tarjan(int u){
dfn[u]=low[u]=++dep;
st[top++]=u;
vis[u]=;
for(int i=head[u]; i!=-; i=edge[i].next){
int v=edge[i].to;
if(!dfn[v]){
Tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(vis[v]){
low[u]=min(low[u],dfn[v]);
}
}
int j;
if(dfn[u]==low[u]){
atype++;
do{
j=st[--top];
belong[j]=atype;
sum[atype]++; //记录每个连通分量中点的个数
vis[j]=;
}
while(u!=j);
}
}
int main(){
while(~scanf("%d",&n)){
init();
for(int i=;i<=n;i++){
scanf("%d",&m);
for(int j=;j<=m;j++){
scanf("%d",&temp);
addedge(i,temp+n);
}
}
for(int i=;i<=n;i++){
scanf("%d",&temp);
addedge(temp+n,i);
}
for(int i=;i<=*n;i++)
if(!dfn[i])
Tarjan(i);
for(int i=;i<=n;i++){
ans.clear();
for(int j=head[i];j!=-;j=edge[j].next){
int v=edge[j].to;
if(belong[i]==belong[v])
ans.push_back(v-n);
}
int sz=ans.size();
sort(ans.begin(),ans.end());
printf("%d",sz);
for(int j=;j<sz;j++){
printf(" %d",ans[j]);
}
puts("");
}
}
}