[poj 1904]King's Quest[Tarjan强连通分量]

时间:2022-03-08 14:05:32

题意:(当时没看懂...)

N个王子和N个女孩, 每个王子喜欢若干女孩. 给出每个王子喜欢的女孩编号, 再给出一种王子和女孩的完美匹配. 求每个王子分别可以和那些女孩结婚可以满足最终每个王子都能找到一个自己喜欢的女孩结婚.(需要避免的情况就是某个王子和自己喜欢的某个女孩结婚之后使得最终无法找到一个完美匹配)

思路:(非独立思考想出...)

将初始的每个完美匹配视为1个节点, u -> v表示u中的王子喜欢v中的女孩, 求这样一个图的强连通分量. 输出每个王子喜欢的,并且和他所在节点在同一个强连通分量中的女孩.

因为在同一个强连通分量中的话,u这个点不管选择哪条与之相连的边(或者不选),都可以使得有一个箭头从它指向的结点再指回它(虽然并不是同一条边),这一条回路上的箭头就表示一种完美匹配.

如果不在同一强连通分量中的话,就没有箭头可以指向它,他的女孩就没有人要了~_~

#include <cstdio>
#include <cstring>
#include <stack>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN = 2005; int dfn[MAXN],low[MAXN],id[MAXN];
bool vis[MAXN];
int size,Index,n,m;
stack<int> s;
vector<int> v[MAXN];
int marry[MAXN];
int ans[MAXN];
void clear()
{
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(id,0,sizeof(id));
memset(vis,false,sizeof(vis));
Index = size = 0;
while(!s.empty()) s.pop();
for(int i=0;i<MAXN;i++)
v[i].clear();
} void Tarjan(int u)
{
low[u] = dfn[u] = ++Index;
vis[u] = true;
s.push(u);
for(int i=0,k;i<v[u].size();i++)
{
k = marry[ v[u][i] ];
if(!dfn[k])
{
Tarjan(k);
low[u] = min(low[u],low[k]);
}
else if(vis[k])
low[u] = min(low[u],low[k]);
}
if(dfn[u]==low[u])
{
size++;
int k;
do
{
k = s.top();s.pop();
vis[k] = false;
id[k] = size;
}while(k!=u);
}
} int main()
{
while(scanf("%d",&n)==1)
{
clear();
for(int i=1,k,t;i<=n;i++)
{
scanf("%d",&k);
while(k--)
{
scanf("%d",&t);
v[i].push_back(t);
}
}
for(int i=1,k;i<=n;i++)
{
scanf("%d",&k);
marry[k] = i;
}
for(int i=1;i<=n;i++)
if(!dfn[i])
Tarjan(i);
for(int i=1;i<=n;i++)
{
int cnt = 0;
for(int j=0;j<v[i].size();j++)
if(id[i]==id[ marry[ v[i][j] ] ])
ans[cnt++] = v[i][j];
sort(ans,ans+cnt);
printf("%d ",cnt);
for(int i=0;i<cnt;i++)
printf("%d%c",ans[i],(i==cnt-1)?'\n':' ');
}
}
}