二分匹配(过山车+Courses+Air Raid)

版权声明:转载请注明出处: https://blog.csdn.net/weixin_43871781/article/details/87542399

先是代码:

int mapp[505][505];
int vis[505],mat[505];
int m,n;
int Find(int s)
{
    for(int i=1;i<=n;i++)
    {
        if(mapp[s][i]&&!vis[i])
        {
            vis[i]=1;
            if(!mat[i]||Find(mat[i]))
            {
                mat[i]=s;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    int k;
    while(~scanf("%d",&k))
    {
        if(k==0)break;
        memset(mapp,0,sizeof(mapp));
        memset(mat,0,sizeof(boy));
        scanf("%d%d",&m,&n);
        int u,v;
        for(int i=0;i<k;i++)
        {
            scanf("%d%d",&u,&v);
            mapp[u][v]=1;
        }
        int ans=0;
        for(int i=1;i<=m;i++)
        {
            memset(vis,0,sizeof(vis));
            if(Find(i))
                ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}

(一)过山车

RPG girls今天和大家一起去游乐场玩,终于可以坐上梦寐以求的过山车了。可是,过山车的每一排只有两个座位,而且还有条不成文的规矩,就是每个女生必须找个个男生做partner和她同坐。但是,每个女孩都有各自的想法,举个例子把,Rabbit只愿意和XHD或PQK做partner,Grass只愿意和linle或LL做partner,PrincessSnow愿意和水域浪子或伪酷儿做partner。考虑到经费问题,boss刘决定只让找到partner的人去坐过山车,其他的人,嘿嘿,就站在下面看着吧。聪明的Acmer,你可以帮忙算算最多有多少对组合可以坐上过山车吗?

Input

输入数据的第一行是三个整数K , M , N,分别表示可能的组合数目,女生的人数,男生的人数。0<K<=1000
1<=N 和M<=500.接下来的K行,每行有两个数,分别表示女生Ai愿意和男生Bj做partner。最后一个0结束输入。

Output

对于每组数据,输出一个整数,表示可以坐上过山车的最多组合数。

Sample Input

6 3 3
1 1
1 2
1 3
2 1
2 3
3 1
0

Sample Output

3

思路:就是找最大匹配数,直接套用模板即可。

代码:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int MAX=1e6+5;
int mapp[505][505];
int vis[505],boy[505];
int m,n;
int Find(int s)
{
    for(int i=1;i<=n;i++)
    {
        if(mapp[s][i]&&!vis[i])
        {
            vis[i]=1;
            if(!boy[i]||Find(boy[i]))
            {
                boy[i]=s;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    int k;
    while(~scanf("%d",&k))
    {
        if(k==0)break;
        scanf("%d%d",&m,&n);
        memset(mapp,0,sizeof(mapp));
        memset(boy,0,sizeof(boy));
        int u,v;
        for(int i=0;i<k;i++)
        {
            scanf("%d%d",&u,&v);
            mapp[u][v]=1;
        }
        int ans=0;
        for(int i=1;i<=m;i++)
        {
            memset(vis,0,sizeof(vis));
            if(Find(i))
                ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}

(二)Courses

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

Your program should read sets of data from a text file. The first line of the input file 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'll 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.

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.

An example of program input and output:

Input

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

Output

YES
NO 

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 

题意:有n个学生和p门课,一个学生可以对多门不同课程感兴趣,现在要选课代表,但有2个条件:

1.每门课都有且仅有一个课代表。

2.每个学生必须成为某门课的课代表,且每个学生代表不同的课程。

如果能满足上述条件,则输出YES,否则输出NO。

思路:如果用课程匹配学生,则把最大匹配数与课程数进行比较,如果用学生匹配课程,则把最大匹配数与学生数进行比较。

代码:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int MAX=1e6+5;
int mapp[505][505];
int own[505],vis[505];
int m,n;
int Find(int s)
{
    for(int i=1;i<=n;i++)
    {
        if(mapp[s][i]&&!vis[i])
        {
            vis[i]=1;
            if(!own[i]||Find(own[i]))
            {
                own[i]=s;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    int k;
    while(~scanf("%d",&k))
    {
        while(k--)
        {
            memset(mapp,0,sizeof(mapp));
            memset(own,0,sizeof(own));
        scanf("%d%d",&m,&n);
        int u,v;
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&u);
            while(u--)
            {
                scanf("%d",&v);
                mapp[i][v]=1;
            }
        }
        int ans=0;
        for(int i=1;i<=m;i++)
        {
            memset(vis,0,sizeof(vis));
            if(Find(i))
                ans++;
        }
            if(ans!=m)
                printf("NO\n");
            else
                printf("YES\n");
        }
    }
    return 0;
}

(三)Air Raid(最小覆盖路径)

Consider a town where all the streets are one-way and each street leads from one intersection to another. It is also known that starting from an intersection and walking through town's streets you can never reach the same intersection i.e. the town's streets form no cycles.

With these assumptions your task is to write a program that finds the minimum number of paratroopers that can descend on the town and visit all the intersections of this town in such a way that more than one paratrooper visits no intersection. Each paratrooper lands at an intersection and can visit other intersections following the town streets. There are no restrictions about the starting intersection for each paratrooper.

Input

Your program should read sets of data. The first line of the input file contains the number of the data sets. Each data set specifies the structure of a town and has the format:

no_of_intersections
no_of_streets
S1 E1
S2 E2
......
Sno_of_streets Eno_of_streets

The first line of each data set contains a positive integer no_of_intersections (greater than 0 and less or equal to 120), which is the number of intersections in the town. The second line contains a positive integer no_of_streets, which is the number of streets in the town. The next no_of_streets lines, one for each street in the town, are randomly ordered and represent the town's streets. The line corresponding to street k (k <= no_of_streets) consists of two positive integers, separated by one blank: Sk (1 <= Sk <= no_of_intersections) - the number of the intersection that is the start of the street, and Ek (1 <= Ek <= no_of_intersections) - the number of the intersection that is the end of the street. Intersections are represented by integers from 1 to no_of_intersections.

There are no blank lines between consecutive sets of data. Input data are correct.

Output

The result of the program is on standard output. For each input data set the program prints on a single line, starting from the beginning of the line, one integer: the minimum number of paratroopers required to visit all the intersections in the town.

Sample Input

2
4
3
3 4
1 3
2 3
3
3
1 3
1 2
2 3

Sample Output

2
1

题意:城镇里的单向街道从一个交叉口连接到另一个交叉口,并且从一个交叉口沿着街道出发不会回到相同的交叉口。伞兵降落在城镇的一个交叉口并可以沿着街道走向另一个交叉口,要求城镇中所有交叉口都被伞兵走过至少需要多少名伞兵。

思路:看懂这条题的要求后,先画出了一张图

从常识方面来说,这张图答案是2,分别是1和4,那这个答案怎么来的呢?

假设每个交叉口只能由一种伞兵通过,我们通过不断匹配去寻找伞兵从某一个交叉路口可以跑向哪个交叉路口,当循环结束后,某个交叉路口没有没路了,说明走过的这条路最少需要一支伞兵。

这就是一个找前驱的过程,当没有前驱时,代表没路了。比如1的前驱是2,2的前驱是3,3的前驱是6,4的前驱是5,5虽然指向2,但是2已经被1走过了,而且1没有其他路可以走,所以先来后到,5没有前驱,6也没有前驱,所以需要2支伞兵。

找前驱的方案可以有多种,比如还有4-5-2-3-6、1,也是两个点没有前驱,也是分成两条路。

代码:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int MAX=1e6+5;
int mapp[505][505];
int vis[505],q[505];
int m,n;
int Find(int s)
{
    for(int i=1;i<=m;i++)
    {
        if(!vis[i]&&mapp[s][i])
        {
            vis[i]=1;
            if(!q[i]||Find(q[i]))
            {
                q[i]=s;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&m,&n);
        memset(mapp,0,sizeof(mapp));
        memset(q,0,sizeof(q));
        int u,v;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&u,&v);
            mapp[u][v]=1;
        }
        int ans=0;
        for(int i=1;i<=m;i++)
        {
            memset(vis,0,sizeof(vis));
            if(Find(i))
                ans++;
        }
        printf("%d\n",m-ans);
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_43871781/article/details/87542399
今日推荐