zoukankan      html  css  js  c++  java
  • POJ 1469 COURSES【匈牙利算法入门 二分图的最大匹配 模板题】

    题目链接:http://poj.org/problem?id=1469

    COURSES
    Time Limit: 1000MS   Memory Limit: 10000K
    Total Submissions: 14455   Accepted: 5715

    Description

    Consider a group of N students and P courses. Each student visits zero, one or more than one courses. Your task is to determine whether it is possible to form a committee of exactly P students that satisfies simultaneously the conditions: 

    • every student in the committee represents a different course (a student can represent a course if he/she visits that course) 
    • each course has a representative in the committee 

    Input

    Your program should read sets of data from the std input. The first line of the input contains the number of the data sets. Each data set is presented in the following format: 

    P N 
    Count1 Student1 1 Student1 2 ... Student1 Count1 
    Count2 Student2 1 Student2 2 ... Student2 Count2 
    ... 
    CountP StudentP 1 StudentP 2 ... StudentP CountP 

    The first line in each data set contains two positive integers separated by one blank: P (1 <= P <= 100) - the number of courses and N (1 <= N <= 300) - the number of students. The next P lines describe in sequence of the courses �from course 1 to course P, each line describing a course. The description of course i is a line that starts with an integer Count i (0 <= Count i <= N) representing the number of students visiting course i. Next, after a blank, you抣l find the Count i students, visiting the course, each two consecutive separated by one blank. Students are numbered with the positive integers from 1 to N. 
    There are no blank lines between consecutive sets of data. Input data are correct. 

    Output

    The result of the program is on the standard output. For each input data set the program prints on a single line "YES" if it is possible to form a committee and "NO" otherwise. There should not be any leading blanks at the start of the line.

    Sample Input

    2
    3 3
    3 1 2 3
    2 1 2
    1 1
    3 3
    2 1 3
    2 1 3
    1 1

    Sample Output

    YES
    NO

    Source

    题意:每门课对应选出一位课代表。

          当前课程的课代表必须是这门课程的学生,而且每人只可当一门课程的代表。

    算法:二分图的最大匹配【模板题】

    分析:分别以课程和学生为点集uv,对应匹配。

    //00K	438MS	C++	1003B 
    #include<cstdio>
    #include<cstring>
    const int maxN=310;
    const int maxP=110;
    int map[maxP][maxN];//建图 
    int match[maxN];//匹配连接 
    bool vis[maxN];//标记 
    int uN,vN;
    bool dfs(int u)
    {
    	for(int v=1;v<=vN;v++)//对应遍历学生 
    	{
    		if(!vis[v] && map[u][v])
    		{
    			vis[v]=true;
    			if(match[v]==-1 || dfs(match[v]))
    			{
    				match[v]=u;
    				return true;
    			}
    		}
    	}
    	return false;
    }
    bool hungary()
    {
    	int sum=0;
    	memset(match,-1,sizeof(match));//未匹配前,初始化 
    	for(int i=1;i<=uN;i++)//遍历每一门课程 
    	{
    		memset(vis,false,sizeof(vis));//找增广路前初始化 
    		if(dfs(i)) sum++;
    	}
    	if(sum==uN) return true;
    	else return false;
    }
    int main()
    {
    	int test;
    	int p,n;
    	int num_stu,student;
    	while(scanf("%d",&test)!=EOF)
    	{
    		while(test--)
    		{
    			scanf("%d%d",&p,&n);
    			uN=p,vN=n;
    			memset(map,0,sizeof(map));
    			for(int i=1;i<=p;i++)
    			{
    				scanf("%d",&num_stu);//选这门课的学生人数 
    				for(int j=1;j<=num_stu;j++)
    				{
    					scanf("%d",&student);
    					map[i][student]=1;
    				}
    			}	
    			if(hungary()) printf("YES\n");
    			else printf("NO\n");
    		}
    	}
    	return 0;
    }

    //300K	438MS	C++	1465B	
    //PS:初次做这种题目时分析的代码。和上面的差不多 
    #include<stdio.h>  
    #include<string.h>  
    int link[310];  
    int n,m;  
    int v[310];  
    int map[110][310];  
      
    bool find(int x)  
    {  
        int i;  
        for(i=1;i<=m;i++)//从第一个人开始查找,把第x节课分配给第i个人  
        {  
            if(!v[i] && map[x][i])//如果第i个人没有被分配课程,并且第i个人选了第x节课  
            {  
                v[i]=1;//第i个人标记为分配了课程  
                if(link[i]==0 || find(link[i]))//如果这门课程没有被分配掉  
                { //或者假如这门课被分配掉了。。然后你看分配的这个学生能不能找到其他选择,有其它选择就把这门课空出来那这个人就可以选了。。  
                    link[i]=x;//标记这门课被选,第i个人选了第x节课  
                    return true;  
                }  
            }  
        }  
        return false;  
    }  
      
    int main()  
    {  
        int test;  
        int i,j;  
        int x,y;  
        int sum;  
        scanf("%d",&test);  
        while(test--)  
        {  
            sum=0;  
            memset(map,0,sizeof(map));  
            memset(link,0,sizeof(link));  
            scanf("%d%d",&n,&m);  
            for(i=1;i<=n;i++)  
            {  
                scanf("%d",&x);  
                for(j=1;j<=x;j++)  
                {  
                    scanf("%d",&y);  
                    map[i][y]=1;//第y个人可以选第i节课 ,就是加一条i到y的有向边  
                }  
            }  
            for(i=1;i<=n;i++)//从第一节课开始分配每一节课  
            {  
                memset(v,false,sizeof(v));  
                if(find(i))//寻找最大匹配。最大匹配就是要不停地找增广路,所以每次都要初始化,重新再找直到找不到了  
                   sum++;  
            }  
            if(sum==n)  
               printf("YES\n");  
            else  
               printf("NO\n");  
        }  
        return 0;  
    }  


  • 相关阅读:
    D. Renting Bikes 二分
    Maximum Absurdity DP + 数学
    模拟 H
    Secrets 数论
    A. Knight Tournament SET的应用
    B. Xenia and Hamming Codeforces 256B GCD,LCM处理字符串
    Alternate Task UVA11728 暴力枚举
    GCD Extreme (II) 欧拉函数的应用
    Bit Magic HDU 4421 2-Sat
    Encoding http://acm.hdu.edu.cn/showproblem.php?pid=1020
  • 原文地址:https://www.cnblogs.com/freezhan/p/2950448.html
Copyright © 2011-2022 走看看