Hiho 117

Hiho 117

时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
学校的秋季运动会即将开始,为了决定参赛人员,各个班又开始忙碌起来。
小Hi和小Ho作为班上的班干部,统计分配比赛选手的重任也自然交到了他们手上。
已知小Hi和小Ho所在的班级一共有N名学生(包含小Hi和小Ho),编号依次为1..N。
运动会一共有M项不同的比赛,编号为1..M。第i项比赛每个班需要派出m[i]名选手参加。
根据小Hi和小Ho的统计,编号为i的学生表示最多同时参加a[i]项比赛,并且给出他所擅长的b[i]项比赛的编号。
小Hi和小Ho希望将每个学生都安排到他所擅长的比赛项目,以增加夺冠的可能性。同时又要考虑满足每项比赛对人数的要求,当然给一个学生安排的比赛项目也不能超过他愿意参加的比赛项目数量。
根据统计的结果,小Hi和小Ho想知道能否有一个合适的安排,同时满足这些条件。

输入
第1行:1个整数T,表示一共有T(2≤T≤5)组数据,每组数据按如下格式给出:
第1行:2个正整数N,M。1≤N≤100,1≤M≤100。
第2行:M个整数,第i个数表示第i个项目需要的选手数量m[i]。1≤m[i]≤N。
第3..N+2行:若干整数,第i+2行表示编号为i的学生的信息。先是a[i],b[i],接下来b[i]个整数,表示其所擅长的b[i]个项目。1≤a[i]≤M
输出
第1..T行:第i行表示第i组数据能否满足要求,若能够输出”Yes”,否则输出”No”。

解题思路
这是一道典型的二分图多重匹配问题,在理解题意后,首先进行构图,然后运行最大流算法,最后总结答案进行输出。

  1. 构图:由题意知,我们是要求从n个学生到m个项目个一个匹配,以
    4 3
    1 2 2
    1 2 1 2
    2 2 1 3
    1 1 2
    1 2 2 3
    为例,有4个学生和3个项目,构图如下:

    源点S到A部分的边的值为a[i],表示第i个学生最多想参加多少项比赛,限制每个学生的流入。 A到B部分为每个学生擅长的项目,若第i个学生擅长第j个项目,则i到j连上一条值为1的边。 B到汇点t部分边的值为m[i],表示第i个项目最多可以流出多少个人。
    这样进行一次最大流算法后,分配的流就是一种分配情况,判断该分配情况则可以得到答案。
  2. 最大流算法:
  3. 输出:根据题意,只需在残余网络图中判断B到t的边的剩余值是否为0即可。

    private static int N = 0, M = 0;
    private static int[,] rGraph = null;
    private static bool HashPath(int[] path)
    {
        Queue<int> q = new Queue<int>();
        q.Enqueue(0);
        bool[] visited = new bool[N + M + 2];
        while (q.Count > 0)
        {
            int node = q.Dequeue();
            for (int i = 0; i < N + M + 2; ++i)
            {
                if (!visited[i] && rGraph[node, i] > 0)
                {
                    q.Enqueue(i);
                    visited[i] = true;
                    path[i] = node;
                }
            }
        }
        return visited[N + M + 1];
    }
    public static void Main()
    {
        int T = int.Parse(Console.ReadLine());
        while (T-- > 0)
        {
            //construct graph
            string[] lineArray = Console.ReadLine().Split(' ');
            N = int.Parse(lineArray[0]);
            M = int.Parse(lineArray[1]);
            rGraph = new int[N + M + 2, N + M + 2];
            lineArray = Console.ReadLine().Split(' ');
            for (int i = 0; i < lineArray.Length; ++i)
                rGraph[i + N + 1, N + M + 1] = int.Parse(lineArray[i]);
            for (int i = 0; i < N; ++i)
            {
                lineArray = Console.ReadLine().Split(' ');
                int a = int.Parse(lineArray[0]);
                rGraph[0, i + 1] = a;
                for (int j = 2; j < lineArray.Length; ++j)
                {
                    int b = int.Parse(lineArray[j]) + N;
                    rGraph[i + 1, b] = 1;
                }
            }
            //maximum flux principle
            int[] path = new int[N + M + 2];
            while (HashPath(path))
            {
                int minCap = int.MaxValue;
                for (int i = N + M + 1; i != 0; i = path[i])
                    if (rGraph[path[i], i] < minCap)
                        minCap = rGraph[path[i], i];
                for (int i = N + M + 1; i != 0; i = path[i])
                {
                    rGraph[path[i], i] -= minCap;
                    rGraph[i, path[i]] += minCap;
                }
            }
            //output the result
            bool flag = true;
            for (int i = 0; i < M; ++i)
            {
                if (rGraph[i + N + 1, N + M + 1] != 0)
                {
                    flag = false;
                    break;
                }
            }
            if (flag)
                Console.WriteLine("Yes");
            else Console.WriteLine("No");
        }
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值