zoukankan      html  css  js  c++  java
  • UOJ #79 一般图最大匹配

    一般图最大匹配

    从前一个和谐的班级,所有人都是搞OI的。有 (n) 个是男生,有 (0) 个是女生。男生编号分别为 (1,…,n)

    现在老师想把他们分成若干个两人小组写动态仙人掌,一个人负责搬砖另一个人负责吐槽。每个人至多属于一个小组。

    有若干个这样的条件:第 (v) 个男生和第 (u) 个男生愿意组成小组。

    请问这个班级里最多产生多少个小组?

    输入格式

    第一行两个正整数,(n,m)。保证 (n≥2)

    接下来 (m) 行,每行两个整数 (v,u) 表示第 (v) 个男生和第 (u) 个男生愿意组成小组。保证 (1≤v,u≤n),保证 (v≠u),保证同一个条件不会出现两次。

    输出格式

    第一行一个整数,表示最多产生多少个小组。

    接下来一行 (n) 个整数,描述一组最优方案。第 (v) 个整数表示 (v) 号男生所在小组的另一个男生的编号。如果 (v) 号男生没有小组请输出 (0)

    限制与约定

    (1≤n≤500)(1≤m≤124750)


    是个板子,因为细节比较复杂我就不说了(其实有的自己也搞不清楚...

    放个代码吧,有一些注释

    Code:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    const int N=510;
    int head[N],to[N*N],Next[N*N],cnt;
    void add(int u,int v)
    {
    	to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
    }
    int F[N],vis[N],clock,pre[N],match[N],q[N*N],l,r,f[N],typ[N],n,m;
    int Find(int x){return f[x]=f[x]==x?x:Find(f[x]);}
    int LCA(int x,int y)
    {
    	for(++clock;;std::swap(x,y))
    		if(x)//防止走过
    		{
    			x=Find(x);//在缩掉的花朵上走 
    			if(vis[x]==clock) return x;
    			else vis[x]=clock,x=pre[match[x]];//一次跳两步 
    		} 
    }
    void shrink(int x,int y,int t)//缩花
    {
    	while(Find(x)!=t)//注意是根到没到 
    	{
    		pre[x]=y,y=match[x];//走x那条链,最开始时末尾两个1类点互指
    		if(typ[y]==2) typ[y]=1,q[++r]=y;//因为不知道奇环的哪个点去匹配,所以都去试试
    		if(Find(x)==x) f[x]=t;//我猜加if和带花树的结构有关
    		if(Find(y)==y) f[y]=t;
    		x=pre[y];//往前跳 
    	}
    } 
    bool path(int st)
    {
    	q[l=r=1]=st;
    	memset(typ,0,sizeof(typ)),memset(pre,0,sizeof(pre));//点的类型和非匹配边
    	for(int i=1;i<=n;i++) f[i]=i;
    	while(l<=r)
    	{
    		int u=q[l++];
    		for(int i=head[u];i;i=Next[i])
    		{
    			int v=to[i];
    			if(typ[v]==2||Find(u)==Find(v)) continue;//已经访问的二类点或者在同一朵花中
    			if(!typ[v])//不在带花树上 
    			{
    				pre[v]=u,typ[v]=2;//成为第二类点 
    				if(!match[v])
    				{
    					int tmp;
    					do
    					{
    						match[tmp=v]=u;
    						v=match[u];
    						match[u]=tmp;
    						u=pre[v];
    					}while(u);
    					return true;
    				}
    				typ[q[++r]=match[v]]=1;//成为1类点进队 
    			} 
    			else//形成了奇环 
    			{
    				int lca=LCA(u,v);
    				shrink(u,v,lca);
    				shrink(v,u,lca);
    			}
    		}	
    	} 
    	return false;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int v,u,i=1;i<=m;i++) scanf("%d%d",&u,&v),add(u,v),add(v,u);
    	int ans=0;
    	for(int i=1;i<=n;i++) ans+=(!match[i]&&path(i));//没匹配过且存在增广路 
    	printf("%d
    ",ans);
    	for(int i=1;i<=n;i++) printf("%d ",match[i]); 
    	return 0;
    }
    

    2018.12.24

  • 相关阅读:
    StrCopy、StrCat、StrPas
    WinAPI: FlashWindow 闪烁窗口
    WinAPI: SetVolumeLabel 设置磁盘卷标
    WinAPI: GetActiveWindow 获取当前活动窗口的句柄
    WinAPI: SetCurrentDirectory、GetCurrentDirectory 设置与获取当前目录
    WinAPI: CreateDirectoryEx 根据模版建立文件夹
    WinAPI: CreateDirectory 建立文件夹
    WinAPI: RemoveDirectory 删除空目录
    WinAPI: GetLogicalDriveStrings 获取系统中存在的逻辑驱动器字符串
    filer.js: 一个 Unix 命令风格的 HTML 5 FileSystem API 封装 V2EX
  • 原文地址:https://www.cnblogs.com/butterflydew/p/10170392.html
Copyright © 2011-2022 走看看