zoukankan      html  css  js  c++  java
  • Steady Cow Assignment(二分图多重匹配+二分)(网络流)

    Steady Cow Assignment
    Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u

    Description

    Farmer John's N (1 <= N <= 1000) cows each reside in one of B (1 <= B <= 20) barns which, of course, have limited capacity. Some cows really like their current barn, and some are not so happy. 

    FJ would like to rearrange the cows such that the cows are as equally happy as possible, even if that means all the cows hate their assigned barn. 

    Each cow gives FJ the order in which she prefers the barns. A cow's happiness with a particular assignment is her ranking of her barn. Your job is to find an assignment of cows to barns such that no barn's capacity is exceeded and the size of the range (i.e., one more than the positive difference between the the highest-ranked barn chosen and that lowest-ranked barn chosen) of barn rankings the cows give their assigned barns is as small as possible.

    Input

    Line 1: Two space-separated integers, N and B 

    Lines 2..N+1: Each line contains B space-separated integers which are exactly 1..B sorted into some order. The first integer on line i+1 is the number of the cow i's top-choice barn, the second integer on that line is the number of the i'th cow's second-choice barn, and so on. 

    Line N+2: B space-separated integers, respectively the capacity of the first barn, then the capacity of the second, and so on. The sum of these numbers is guaranteed to be at least N.

    Output

    Line 1: One integer, the size of the minumum range of barn rankings the cows give their assigned barns, including the endpoints.

    Sample Input

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

    Sample Output

    2

    Hint

    Explanation of the sample: 

    Each cow can be assigned to her first or second choice: barn 1 gets cows 1 and 5, barn 2 gets cow 2, barn 3 gets cow 4, and barn 4 gets cows 3 and 6.

    网友的不错,仿一下。。。大笑,其实网络流大同小异

    题目描述:

      有n头奶牛,m个棚,每个奶牛对每个棚都有一个喜爱程度。当然啦,棚子也是有脾气的,并不是奶牛想住进来就住进来,超出棚子的最大容量了,棚子是拒绝的。现在要给每个奶牛安家,本宝宝是一个公正无私的人类,所以要找一个奶牛喜爱程度差值最小的方案(虽然这样大家的喜爱程度可能普遍偏低,因为绝对公平并不代表合理啊),问喜爱程度的区间最小为多大?

    解题思路:

      每个棚子并不是住一个奶牛,所以是多重匹配咯。匹配的时候二分枚举喜爱程度的区间大小,根据区间大小来枚举区间的起点和终点,然后跑多重匹配判断是否合法即可。注意咯,求得是区间大小。还有啊,还有啊,数据读入的时候maps[i][j]并不是i_th奶牛对j_th棚子的喜爱值,而是i_th奶牛对maps[i][j]棚子的喜爱程度为j。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int maxn = 1010;
    int maps[maxn][22], vis[22], used[22][maxn];
    int link[22], limit[22], n, m, s, e, mid;
    bool Find (int u)
    {
        for (int i=1; i<=m; i++)
        {//多重匹配
            if (!vis[i] && maps[u][i]<e && s<=maps[u][i])
            {
                vis[i] = 1;
                if (link[i] < limit[i])
                {//i棚子未满
                    used[i][link[i] ++] = u;
                    return true;
                }
                for (int j=0; j<limit[i]; j++)//i棚子已满,寻找增广路
                    if (Find(used[i][j]))
                    {
                        used[i][j] = u;
                        return true;
                    }
            }
        }
        return false;
    }
    bool hungry ()
    {
        for (s=1; s<=m+1-mid; s++)
        {//枚举区间起点与终点
            int ans = 0;
            e = s + mid;
            memset (link, 0, sizeof(link));
            for (int i=1; i<=n; i++)
            {
                memset (vis, 0, sizeof(vis));
                if (Find (i))
                    ans ++;
            }
            if (ans == n)
                return true;
        }
        return false;
    }
    int main ()
    {
        while (scanf ("%d %d", &n, &m) != EOF)
        {
            for (int i=1; i<=n; i++)
                for (int j=1; j<=m; j++)
                {
                    scanf ("%d", &mid);
                    maps[i][mid] = j;
                }
            for (int i=1; i<=m; i++)
                scanf ("%d", &limit[i]);
            int left = 1, right = m, ans = 0;
            while (left<=right)
            {//二分枚举区间
                mid = (right+left)/2;
                if (hungry())
                    {
                        ans = mid;
                        right = mid - 1 ;
                    }
                else
                    left = mid + 1 ;
            }
            printf ("%d
    ", ans);
        }
        return 0;
    }




  • 相关阅读:
    oracle创建函数和调用存储过程和调用函数的例子(区别)
    oracle存储过程的创建和使用
    oracle恢复已删除数据
    存储管理工具StorageExplorer的基本使用
    Azure CLI对ASM,ARM资源的基本操作
    Windows系统安装Azure CLI
    Azure Powershell对ASM资源的基本操作
    Azure Powershell对ARM资源的基本操作
    安装Windows Azure Powershell
    Linux虚拟机之间实现密钥登陆
  • 原文地址:https://www.cnblogs.com/zswbky/p/6717974.html
Copyright © 2011-2022 走看看