O - Steady Cow Assignment[二分查找+匹配+遍历]

O - Steady Cow Assignment

题意大概是,又是一个农民,他有N头牛,B个牛棚。而这些牛对于这些牛棚都有自己的看法,并给出了自己对于这些牛棚的喜爱程度。而每个牛棚呢又都有牛的头数的限制,所以不是所有的牛都选上自己的第一志愿。要求的是志愿数的最大宽度的最小值。。

这里有一个坑。。他要求的是志愿排序的最大宽度的最小值,但并没有说以第一志愿为标准。所以我们都要看一遍。这里就有一个遍历的过程了。
而其他的和之前的二分查找+匹配几乎一样。只是有一条条件不一样了,就是在匹配的时候,我们要求图的那个点的志愿排名大于等于L, 小于等于R。 然后遍历不能写到judge函数里面去,写进去怎样都不太对,我们只有在外层进行遍历,然后一个一个找起点,进行宽度测试。这里就用到了二分的思想了。

int m[len][25];
int vis[len], l[len][len];
int cow[len];//牛棚的最大数
int cnt[len];
int N, B;
int main()
{
    while(cin >> N >> B)
    {
        int num;
        for (int i=0; i<N; i++)
        {
            for (int j=0; j<B; j++)
            {
                cin >> num;
                m[i][num-1] = j;//排序,从0开始所以减一
            }
        }

        for (int i=0; i<B; i++)
            cin >> cow[i];

        int L=0, R=B, ans, mid, i;
        while (L<R)
        {
            mid = (L + R) / 2;
            for (i=0; i<B; i++){
                if (judge(i, i+mid)) break;
            }//这个循环就是一次遍历,也是枚举
            
            if (i<B)
            {
                ans = mid;
                R = mid;
            }
            else
            {
                L = mid + 1;
            }

        }
//        cout << endl;
//        for (int i=0; i<N; i++){
//            for (int j=0; j<cow[i]; j++){
//                cout << l[i][j] << " ";
//            }
//            cout << endl;
//        }
//        cout << endl;

        cout << ans+1 << endl;
    }
    return 0;
}
bool judge(int L, int R)
{
    memset(cnt, 0, sizeof(cnt));
    for (int j=0; j<N; j++)
    {
        memset(vis, 0, sizeof(vis));
        if (!find(j, L, R))
            return false;
    }
    return true;
}
bool find(int p, int L, int R)
{
    for (int i=0; i<B; i++)
    {
        if (m[p][i]>=L && m[p][i]<=R && !vis[i])
        {
            vis[i] ++;
            if (cnt[i]<cow[i])
            {
                l[i][cnt[i] ++] = p;
                return true;
            }
            else
            {
                for (int j=0; j<cnt[i]; j++)
                {
                    if (find(l[i][j], L, R))
                    {
                        l[i][j] = p;
                        return true;
                    }
                }
            }
        }
    }
    return false;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值