当前位置: 代码迷 >> 综合 >> poj 1904 King's Quest 强连通分量
  详细解决方案

poj 1904 King's Quest 强连通分量

热度:90   发布时间:2024-01-19 06:24:41.0

题意:

有n男n女,每个男的可能喜欢多个女的,男的只能跟自己喜欢的人结婚,现在对每个男的要求一个女子集合,使当他跟其中任何女的结婚后其他的n-1个男的都还有喜欢的女孩可以结婚。输入还给出一组可行的结婚方案。

思路:
经典构图题,把输入给的结婚方案中的n对男女看做n个顶点,如果i对中的男喜欢j对中的女则有一条i到j的有向边,然后求强联通分量,跟男的i在一个联通分量内的女的只要i喜欢都可以娶。

代码:

//poj 1904
//sepNINE
#include <iostream>
#include <vector>
#include <stack>
#include <algorithm>
using namespace std;
const int maxN=2048;
const int maxM=200048;
vector<int> son[maxN],ans[maxN];
int h[maxN],head[maxN],belong[maxN],dfn[maxN],low[maxN],ins[maxN];
int n,e,index,cnt;
stack<int> s;
struct Edge{int v,next;
}edge[maxM];
void addEdge(int a,int b)
{edge[e].v=b;edge[e].next=head[a];head[a]=e++;
}void tarjan(int u)
{dfn[u]=low[u]=++index;s.push(u);ins[u]=1;for(int i=head[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(ins[v]==1)low[u]=min(low[u],dfn[v]);}int k;if(low[u]==dfn[u]){++cnt;do{k=s.top();s.pop();ins[k]=0;belong[k]=cnt;}while(dfn[k]!=low[k]);}
} 
int main()
{int i,j;e=0;memset(head,-1,sizeof(head));scanf("%d",&n);for(i=1;i<=n;++i){int x;scanf("%d",&x);while(x--){int a;scanf("%d",&a);son[i].push_back(a);}sort(son[i].begin(),son[i].end());}for(i=1;i<=n;++i){int a;scanf("%d",&a);h[a]=i;}for(i=1;i<=n;++i){int num=son[i].size();for(j=0;j<num;++j){int y=h[son[i][j]];if(y!=i)addEdge(i,y);	}}memset(dfn,0,sizeof(dfn));memset(ins,0,sizeof(ins));while(!s.empty()) s.pop();index=cnt=0;for(i=1;i<=n;++i)if(!dfn[i])tarjan(i);for(i=1;i<=n;++i)for(j=0;j<son[i].size();++j)if(belong[i]==belong[h[son[i][j]]])ans[i].push_back(son[i][j]);for(i=1;i<=n;++i){int num=ans[i].size();printf("%d",num);for(int j=0;j<num;++j)printf(" %d",ans[i][j]);printf("\n");}return 0;	
}