SSL 2061_牛棚安排_匹配

lzusa 发布于 2018-01-06 3 次阅读


题目描述

Farmer John的N(1<=N<=1000)头奶牛分别居住在农场所拥有的B(1<=B<=20)个牛棚的某一个里。有些奶牛很喜欢她们当前住的牛棚,而另一些则讨厌再在它们现在所在的牛棚呆下去。 
FJ在忍受了若干次奶牛的抱怨后,决定为所有奶牛重新安排牛棚,使最不满的那头奶牛与最高兴的奶牛的心情差异最小,即使这会让所有奶牛都更加郁闷。 
每头奶牛都把她对各个牛棚的好感度从高到低排序后告诉了FJ。当然,如果一头奶牛被安排到的牛棚在她给出的列表中越靠后,她就会越郁闷。你可以认为奶牛的郁闷指数是她被分配到的牛棚在列表中的位置。奶牛们是斤斤计较的,她们无法容忍别的奶牛在自己喜欢的牛棚里快乐地生活,而自己却呆在一个自己不喜欢的牛棚里。每个牛棚都只能容纳一定数量的奶牛。FJ希望在每个牛棚都没有超出容量限制的前提下,使最郁闷和最高兴的奶牛的郁闷指数的跨度最小。 
FJ请你帮他写个程序,来计算这个最小的郁闷指数跨度到底是多少。


 

思路

我们可以枚举一个放的区间,将每一个牛棚拆为若干个点,用匹配判断当前的方案是否可行

#include 
#include 
#include 
using namespace std;
#define fill(x, y) memset(x, y, sizeof(x))
#define max(x, y) ((x) > (y) ? (x) : (y))
int l, r, n, m;
int tot[31], a[1001][31], p[31][1001], ans;
bool fl[31];
int tarjan(int now)
{
    for (int i = l; i <= r; i++)
    {
        int t = a[now][i];
        if (p[t][0] < tot[t])
        {
            p[t][0]++;
            p[t][p[t][0]] = now;
            return 1;
        }
        else if (!fl[t])
        {
            fl[t] = 1;
            for (int j = 1; j <= p[t][0]; j++)
            {
                if (tarjan(p[t][j]))
                {
                    p[t][j] = now;
                    return 1;
                }
            }
        }
    }
    return 0;
}
int work()
{
    ans = 0x7f7f7f7f;
    for (l = 1; l <= m; l++)
    {
        fill(p, 0);
        r = l;
        for (int i = 1; i <= n; i++)
        {
            while (1)
            {
                fill(fl, 0);
                if (tarjan(i)) break;
                r++;
                if (r > m) break;
                if (r - l + 1 >= ans) break;
            }
            if (r - l + 1 >= ans) break;
        }
        if (r <= m && r - l + 1 < ans) ans = r - l + 1;
    }
}
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            scanf("%d", &a[i][j]);
    for (int i = 1; i <= m; i++)
        scanf("%d", &tot[i]);
    work();
    printf("%d\n", ans);
}

 


 

]]>