zoukankan      html  css  js  c++  java
  • 【POJ1469】Courses-二分图最大匹配

    测试地址:Courses

    题目大意:有P门课程和N个学生,要求从这些学生中取出P个组成委员会,要求:(1)委员会中的每个学生都代表不一样的课程(一个学生上一门课程,他就可以代表这门课程)。(2)委员会中每门课程都有不同的学生代表。问存不存在这样的委员会组建方案。

    做法:裸的二分图最大匹配,这里直接套Hungary(匈牙利)算法即可。

    2017.3.7更新:用理论上更优的Hopcroft-Karp算法又做了一遍,一并贴在这里。

    以下是本人代码:

    Hungary(匈牙利)算法:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int T,n,p,tot=0,match,first[110],mat[310];
    struct {int v,next;} e[100010];
    bool used[310];
    
    void insert(int a,int b)
    {
      e[++tot].v=b;
      e[tot].next=first[a];
      first[a]=tot;
    }
    
    bool crosspath(int x) //返回一个布尔值,表示存不存在从x出发的交错链
    {
      for(int i=first[x];i;i=e[i].next)
      {
        int j=e[i].v;
    	if (!used[j])
    	{
    	  used[j]=1;
    	  if (mat[j]==0||crosspath(mat[j]))
    	  {
    	    mat[j]=x;
    		return 1;
    	  }
    	}
      }
      return 0;
    }
    
    void hungary() //Hungary(匈牙利)算法
    {
      for(int i=1;i<=p;i++)
      {
        memset(used,0,sizeof(used));
        if (crosspath(i))
    	  match++;
      }
    }
    
    int main()
    {
      scanf("%d",&T);
      while(T--)
      {
        scanf("%d%d",&p,&n);
    	memset(first,0,sizeof(first));
    	memset(mat,0,sizeof(mat));
    	match=tot=0;
    	for(int i=1;i<=p;i++)
    	{
    	  int cnt;
    	  scanf("%d",&cnt);
    	  while(cnt--)
    	  {
    	    int a;
    		scanf("%d",&a);
    		insert(i,a);
    	  }
    	}
    	if (p>n) {printf("NO
    ");continue;} //课程数多于学生数,不可能有满足条件的方案
    	hungary();
    	if (p==match) printf("YES
    ");
    	else printf("NO
    ");
      }
      
      return 0;
    }
    

    Hopcroft-Karp算法:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #define inf 999999999
    using namespace std;
    int p,n,dis,T;
    int bmap[110][310];
    int cx[110],cy[310],dx[110],dy[310];
    bool vis[310];
    
    bool searchpath()
    {
      queue<int> q;
      dis=inf;
      memset(dx,-1,sizeof(dx));
      memset(dy,-1,sizeof(dy));
      for(int i=1;i<=p;i++)
      {
        if (cx[i]==-1)
    	{
    	  q.push(i);
    	  dx[i]=0;
    	}
      }
      while(!q.empty())
      {
        int u=q.front();q.pop();
    	if (dx[u]>dis) break;
    	for(int i=1;i<=n;i++)
    	{
    	  if (bmap[u][i]&&dy[i]==-1)
    	  {
    	    dy[i]=dx[u]+1;
    		if (cy[i]==-1) dis=dy[i];
    		else
    		{
    		  dx[cy[i]]=dy[i]+1;
    		  q.push(cy[i]);
    		}
    	  }
    	}
      }
      return dis!=inf;
    }
    
    int findpath(int u)
    {
      for(int i=1;i<=n;i++)
      {
        if (!vis[i]&&bmap[u][i]&&dy[i]==dx[u]+1)
    	{
    	  vis[i]=1;
    	  if (cy[i]!=-1&&dy[i]==dis)
    	  {
    	    continue;
    	  }
    	  if (cy[i]==-1||findpath(cy[i]))
    	  {
    	    cy[i]=u,cx[u]=i;
    	    return 1;
    	  }
    	}
      }
      return 0;
    }
    
    int maxmatch()
    {
      int ans=0;
      memset(cx,-1,sizeof(cx));
      memset(cy,-1,sizeof(cy));
      while(searchpath())
      {
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=p;i++)
    	{
    	  if (cx[i]==-1)
    	  {
    	    ans+=findpath(i);
    	  }
    	}
      }
      return ans;
    }
    
    int main()
    {
      scanf("%d",&T);
      while(T--)
      {
        scanf("%d%d",&p,&n);
    	memset(bmap,0,sizeof(bmap));
    	for(int i=1,k;i<=p;i++)
    	{
    	  scanf("%d",&k);
    	  for(int j=1,a;j<=k;j++)
    	  {
    	    scanf("%d",&a);
    		bmap[i][a]=1;
    	  }
    	}
    	
    	if (maxmatch()==p) printf("YES
    ");
    	else printf("NO
    ");
      }
      
      return 0;
    }
    


  • 相关阅读:
    添加组合索引时,做相等运算字段应该放在最前面
    常用位运算
    redis php扩展简单使用
    mysql优化之简单概念
    mysql优化之sql语句优化
    简单画图 gd库函数
    win下 安装mongodb
    伪静态之实际应用
    tomcat win简单配置
    docker
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793913.html
Copyright © 2011-2022 走看看