zoukankan      html  css  js  c++  java
  • 求出二分图所有可能的匹配边

    pku 1904

    题目大意是有一个国王,他有n个儿子,现在有n个美丽的女子准备嫁给他的n个儿子。国王已经让他的大臣收集了每个儿子喜欢的姑娘的编号(可以喜欢很多个),并且大臣们已经找出了一个完美匹配的方案。现在国王不满意,他想要知道所有可能的匹配方案(前提是每个儿子可以娶到一个姑娘)。即求出每个儿子所有可能的结婚方案。

    这题的解法是:

    1、根据题目信息建图(王子->姑娘)。

    2、根据题目给定的完美匹配建图(姑娘->王子)。

    3、求强连通分量

    4、如果某个姑娘和王子在一个连通分量,并且他们之间在原图上存在直接边,那么这个姑娘便是王子的可能匹配

    分析:

    根据题意,每个王子喜欢的姑娘已经确定了,他只能娶他喜欢的。既然是n个王子,n个姑娘。也就是说,最终最终还是一对一,即每个王子必须要有一个老婆。

    假如某一个王子已经和一个姑娘完美匹配了,现在可能存在其他方案,假如这个方案中,王子a和王子b喜欢的某一个姑娘匹配,那么对于王子b来说,他就少了一个老婆的选择了,那怎么办呢?他就只能再去匹配上一个别的王子的姑娘。一次类推,那么这个王子怎么办呢?很有可能最后一个王子便没有老婆了。如果要避免最后一个王子没有老婆的情况发生,那么他就只能管第一个王子要了,谁让他抢走了别人的姑娘呢。这么一折腾,就形成了一个环,也就是一个强连通分量。也就是说,在一个强连通分量里,王子间是可以相互交换老婆的...那么为什么还要原图存在直接边呢?因为直接边说明王子喜欢这个女孩,如果他要了一个自己不喜欢的,那么别的王子自然会少掉一个喜欢的女孩。这是不道德的~

    下面是代码:

    #include<iostream>
    #include<string>
    #include<stack>
    using namespace std;
    
    typedef struct node
    {
    	int v;
    	struct node *next;
    }node;
    
    node *link[5000];
    node edge[400000];
    int num,n;
    
    void add(int u,int v)
    {
    	edge[num].v=v;
    	edge[num].next=link[u];
    	link[u]=edge+num++;
    }
    
    int find(int u,int v)
    {
    	for(node *p=link[u];p;p=p->next)
    	{
    		if(p->v==v)
    			return 1;
    	}
    	return -1;
    }
    
    int dnf[5000],low[5000],instack[5000],belong[5000];
    int cut,mm;
    stack<int>Q;
    
    void tarjan(int u)
    {
    	low[u]=dnf[u]=++mm;
    	instack[u]=1;
    	Q.push(u);
    	for(node *p=link[u];p;p=p->next)
    	{
    		if(!dnf[p->v])
    		{
    			tarjan(p->v);
    			if(low[u]>low[p->v])
    			{
    				low[u]=low[p->v];
    			}
    		}
    		else if(instack[p->v] && low[u]>dnf[p->v])
    		{
    			low[u]=dnf[p->v];
    		}
    	}
    	int v;
    	if(low[u]==dnf[u])
    	{
    		cut++;
    		do
    		{
    			v=Q.top();
    			Q.pop();
    			instack[v]=0;
    			belong[v]=cut;
    		}while(u!=v);
    	}
    }
    
    void solve()
    {
    	cut=0;
    	mm=0;
    	memset(instack,0,sizeof(instack));
    	memset(dnf,0,sizeof(dnf));
    	for(int i=1;i<=2*n;i++)
    	{
    		if(!dnf[i])
    			tarjan(i);
    	}
    }
    
    int main()
    {
    	int i,j,k,a;
    	freopen("D:\\in.txt","r",stdin);
    	while(scanf("%d",&n)!=EOF)
    	{
    		memset(link,0,sizeof(link));
    		num=0;
    		for(i=1;i<=n;i++)
    		{
    			scanf("%d",&k);
    			for(j=1;j<=k;j++)
    			{
    				scanf("%d",&a);
    				add(i,a+n);
    			}
    		}
    		for(i=1;i<=n;i++)
    		{
    			scanf("%d",&a);
    			add(a+n,i);
    		}
    		solve();
    		int ans[2001];
    		for(i=1;i<=n;i++)
    		{
    			k=0;
    			for(j=n+1;j<=2*n;j++)
    			{
    				if(belong[i]==belong[j] && find(i,j)!=-1)
    				{
    					ans[k++]=j-n;	
    				}
    			}
    			printf("%d",k);
    			for(j=0;j<k;j++)
    			{
    				printf(" %d",ans[j]);
    			}
    			printf("\n");
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    UVa 12174 (滑动窗口) Shuffle
    UVa 1607 (二分) Gates
    CodeForces ZeptoLab Code Rush 2015
    HDU 1525 (博弈) Euclid's Game
    HDU 2147 (博弈) kiki's game
    UVa 11093 Just Finish it up
    UVa 10954 (Huffman 优先队列) Add All
    CodeForces Round #298 Div.2
    UVa 12627 (递归 计数 找规律) Erratic Expansion
    UVa 714 (二分) Copying Books
  • 原文地址:https://www.cnblogs.com/ka200812/p/2122013.html
Copyright © 2011-2022 走看看