poj 1904 King's Quest 二分图中强联通分量的运用

/*
题意:给你一个二分图,给定初始的完全匹配,判断更改某个X集合的匹配对象,时候还存在完全匹配
题解:强联通分量,对于非初始匹配的边,建由X到Y的单向边,反正建由Y到X的单向边,由增广路原理可知道,非初始匹配边只要在同一个强联通分量里面,必然可以重构一个完全匹配
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<climits>
#include<vector>
using namespace std;
const int MAXV=4009;
int n;
struct Person
{
	int n;//X集合的出边出度
	int q[2001];//与i向量的Y中元素
}p[2001];
struct Edge
{
	int v,next;
}edge[MAXV*MAXV];
int first[MAXV],Link[MAXV],ins[MAXV],dfn[MAXV],low[MAXV],Stack[MAXV],scc[MAXV],ans[MAXV];
int e,top,index,num;
void add(int u,int v)
{
	edge[e].v=v;
	edge[e].next=first[u];
	first[u]=e++;
}
void tarjan(int u)  
{  
    int v;  
    low[u] = dfn[u] = index++;  
    Stack[++top]=u; 
    ins[u] = true;  
    // 枚举每一条边:u-->v  
    for (int k=first[u]; k!=-1; k=edge[k].next)  
    {  
        v = edge[k].v;  
        if (dfn[v] == 0)  
        {  
            tarjan(v);  
            low[u]=min(low[u],low[v]);  
        }  
        else if (ins[v])  
        {  
            low[u]=min(low[u],dfn[v]);  
        }  
    }  
    // 如果节点u是强连通分量的根  
    if (dfn[u] == low[u])  
    {  
        num++;  
        do  
        {  
            v = Stack[top--];  
            ins[v] = false;  
            scc[v] = num;  
        }while (u != v);  
    }  
}  
void solve()
{
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<p[i].n;j++)
		{
			if(Link[i]!=p[i].q[j]+n)
			{
			add(i,p[i].q[j]+n);
			}
			else 
			{
			add(p[i].q[j]+n,i);
			}
		}
	}
	memset(dfn,0,sizeof(dfn));
	memset(low,0,sizeof(low));
	memset(ins,0,sizeof(ins));
	memset(scc,0,sizeof(scc));
	index=1;
	top=-1;
	num=0;
	for(int i=1;i<=2*n;i++)
	{
		if(dfn[i]==0)
		{
		//cout<<i<<endl;
		tarjan(i);
		}
	}
	int key=0;
	for(int i=1;i<=n;i++)
	{
		key=0;
		for(int j=0;j<p[i].n;j++)
		if(scc[p[i].q[j]+n]==scc[i])
		{
			ans[key++]=p[i].q[j];
		}
		if(key==0)
		{
			ans[key++]=Link[i]-n;
		}
		sort(ans,ans+key);
		printf("%d",key);
		for(int i=0;i<key;i++)
		{
			printf(" %d",ans[i]);
		}
		printf("\n");
	}
}
int main()
{
	int tmp,k;
	while(scanf("%d",&n)!=EOF)
	{
		memset(first,-1,sizeof(first));
		memset(Link,-1,sizeof(Link));
		e=0;
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&p[i].n);
			for(int j=0;j<p[i].n;j++)
			{
				scanf("%d",&p[i].q[j]);
			}
		}
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&tmp);
			Link[i]=tmp+n;//X集合中i的初始匹配
		}
		solve();
	}
return 0;
}

你可能感兴趣的:(struct)