[bzoj3371][poj2009][Usaco2004 Mar]Moo University - Emergency Pizza Order 定制比萨饼

标题这么长的。。真是让感觉人头大脚轻。

这道题我并没有A,拿到了80pts。做法基于二分图匹配但还包含贪心。很玄乎,给大家提供思路而已。

贴题面先。



Description

Moo大学的餐厅必须为$C(1\leq C\leq 1000)$头入学的奶牛新生定制比萨饼.比萨饼可以在比萨小屋订做.一个饼只能给一头奶牛吃.尽管比萨小屋想为每一头奶牛都做一个比萨饼,但是他们必须服从以下三个条件:

·比萨小屋拥有$T(1\leq T\leq 30)$种素菜馅,每个比萨饼有且仅有$K(1\leq K\leq T)$种馅。

·任何一个比萨饼里不能有两种相同的馅(比如一个比萨饼里不能有两份洋葱)。

·任何两个比萨饼不能有完全相同的馅,即任何两个比萨饼至少有一种馅是不同的。当然,馅的编号是1到T。

Moo大学的奶牛对比萨饼馅十分挑剔,有的奶牛可能什么馅都不喜欢。一头奶牛只吃那种所有的馅他都喜欢的比萨饼。

请你计算最多能喂几头奶牛。

Input

第1行:三个整数C,T,K.

第2到C+1行:每行有若干个用空格分开的整数,表示这头奶牛喜欢的馅.第一个数是这头奶牛喜欢的馅的种数.接下来的几个整数是这头奶牛喜欢的馅的编号。

Output

一个整数,即最多能有几头牛被喂养。

Sample Input

3 2 1

2 2 1

1 1

1 2

Sample Output

2

样例说明

只能生产两种饼:一个有1号馅的比萨饼和一个有2号馅的比萨饼。第一个饼给第1号牛,第二块饼给3号牛,这样两头牛被喂饱了.同时将三头都喂饱的办法不存在。



题面并不是很容易看懂,理解应该是没问题的。重要的几句话是:

1:不能有两头牛的pizza组成完全相同。

2:一个pizza上必须有且仅有k种馅料。

3:pizza上的馅料不能重复。

以上就是说每头牛的喜好与pizza的构成可以用一个01串或者bitset来表示,且是1的位有且只有k个,pizza之间互不相同。

4;一头牛能与一个pizza匹配当且仅当牛的01串中为0的位,pizza的01串也是0。

看起来就是个二分图匹配,但是数据范围?有30种馅料,最多可以存在$\binom{15}{30}$大约$1e12$种pizza。但最终能匹配的能有几个?显然不会超过n。如果枚举所有的点,连上所有的边,额,呵呵。

所以显然不能按上面说的那样来做。需要在寻找增广路的时候,动态寻找。

具体实现:

首先能跟给定奶牛匹配的pizza,我们说过,必须在奶牛为0的位上也是0。但我们要凑够k种馅料,所以还需要在保证上述要求的情况下,填上k个1。我们假设当前奶牛喜欢t种馅,即不喜欢m-t种馅,即有m-t位为0。显然t<k的牛什么也给不了,挑食太多就没法满足。其他的牛呢?我们这k位怎么填?我的做法是按照枚举的顺序填就行,先向靠前的位填1,直到填完。然后我们得到一个01串,可以将其转成int之后用map来存储这个pizza是否被其他牛占领过了。

下面是出现问题的地方。

如果已经被占领过,比较当前牛和之前占领的牛哪一个喜欢的馅料多。由喜欢馅料多的牛做出让步,把这个pizza让给少的,因为它更矫情,更难满足。而且如果两头牛能一起抢一个pizza,pizza一定是两头牛的喜好的交集。这个贪心我并不会证明是正确的,而且最尴尬的在于两头牛喜欢的馅料数相等,还不完全相同,比如(1,3,4)和(3,4,5)抢(3,4),并不好说给谁。我的做法里默认先来后到,所以会有错误。

略过这里不提,按如上方法增广,如果不能增广就表示这个牛匹配不到pizza。每头牛匹配完,即可得出答案。

Tips:其实还有很难解决的一个地方,就是如何按顺序枚举在(m-t)个空位上填入k个1。我发现了一位博主的做法用了上去。很强。



因为还没有做出正解,所以希望有dalao可以切掉这道题并告诉本蒟蒻怎么解决错误的贪心或者正解也好!

附80pts

#include<iostream>
#include<cstdio>
#include<bitset>
#include<map>
using namespace std;
map<int,int>g;
int n,m,k,cnt=0;
int nxtC(int k,int lim){
    int ret,b=k&-k,t=(k+b);
    ret=(((t^k)>>2)/b)|t;
    if(ret>=1<<lim)
    return 0;
    return ret;
}
void find(int x){
    bitset<32>b(x);
    int f[32],top=0,c=m-b.count();
    for(int i=0;i<m;i++)
    if(b[i])f[top++]=i;
    int ik=(1<<k)-1;
    do{
        bitset<32>t;
        for(int i=0;i<top;i++)
        if(ik&(1<<i))
        t[f[i]]=1;
        int y=t.to_ulong();
        if(!g[y]){
            g[y]=x;cnt++;return;
        }
        else{
            int r=g[y];
            bitset<32>tmp(r);
            if(tmp.count()<=m-c)
            continue;
            g[y]=x;
            find(r);
            return;
        }
    }while(ik=nxtC(ik,top));
}
int main(){
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++){
        int t;scanf("%d",&t);
        bitset<32>p;
        for(int i=1;i<=t;i++){
            int x;scanf("%d",&x);
            p[x-1]=1;
        }
        if(t<k)continue;
        find(p.to_ulong());
    }
    cout<<cnt;
}


注:nxtC(int k,int lim)即求出当前为k(int表示的01串)的下一个$\binom{K}{lim}$组合。

如:nxC(11(10102),5)返回的应该是12(11002),即四选二的1010的下一个组合。枚举顺序从小到大。

注意函数带的参数k并不是组合数里的K。我的变量有的定义在函数里有的是全局,组合数的K是全局的那个,但在nxC函数里是失效的,也就是说nxC函数并不需要知道要填几个1,因为根据上一个状态就能知道有几个1了。

时间: 2024-10-12 07:02:28

[bzoj3371][poj2009][Usaco2004 Mar]Moo University - Emergency Pizza Order 定制比萨饼的相关文章

bzoj 3373: [Usaco2004 Mar]Lying Livestock 说谎的牲畜

3373: [Usaco2004 Mar]Lying Livestock 说谎的牲畜 Description 兽群中总是有一些麻烦制造者.约翰知道他的N(1≤N≤100)头奶牛中有一头总是说谎,其他的总是说真话.他想快速的找出这个麻烦制造者.为了实现这个目标,他一个一个的问这些奶牛Q(1≤Q≤1000)个关于它们吃草的简单问题(虽然大多数奶牛是诚实的但它们依旧很笨只能懂得一些关于食物的话题). 他将这些问题用以下的格式写了下来: 牛4说:牛5比牛10吃得多 牛6说:牛10比牛7吃得多 牛3说:牛

poj2010 Moo University - Financial Aid

Moo University - Financial Aid 题意: 一个私立学校的学生要申请奖学金,而学校的金额有限.因此,学校希望在金额不超过F的情况下从C中选得N对数. 给出三个数N,C,F.分别代表在C对数中要取得N对数. 而每对数分别代表成绩,跟申请金额.要求取得N对数中的总金额不超过F的条件下,然取得中间的以为学生的成绩最高.(N为even) 算法分析: 本题有两种解法,一种是用优先队列,一种是二分; 一.利用堆实现 先说堆的实现方法,我们能够现对头尾的N/2进行处理,由于头尾的N/

bzoj3374[Usaco2004 Mar]Special Serial Numbers 特殊编号*

bzoj3374[Usaco2004 Mar]Special Serial Numbers 特殊编号 题意: 求比一个数大的最小的一半以上的数位相同的数.数位数≤100. 题解: 模拟题.从低位枚举到高位,对于每一位枚举比原数该位大的数,同时枚举这一位之后要由0和哪一个数组成,最后得到一个最小的数输出.具体看代码. 有点像NOIP的那道Jam的计数法. 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <algor

Moo University - Financial Aid (poj 2010 优先队列 或者 二分)

Language: Default Moo University - Financial Aid Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 5551   Accepted: 1663 Description Bessie noted that although humans have many universities they can attend, cows have none. To remedy this p

bzoj3375[Usaco2004 Mar]Paranoid Cows 发疯的奶牛*

bzoj3375[Usaco2004 Mar]Paranoid Cows 发疯的奶牛 题意: 依次给出n只奶牛的产奶时间段,求最大的k使得前k只奶牛不存在一个时间段被另一个时间段完全覆盖的情况.n≤100000. 题解: 设当前在处理第i只奶牛,前i-1只奶牛都合法.那么如果前i-1只奶牛中时间段左端点小于且最接近第i只奶牛时间段左端点的奶牛右端点大于当前奶牛则不合法,且如果前i-1只奶牛中时间段左端点大于且最接近第i只奶牛时间段左端点的奶牛右端点小于第i只奶牛则不合法,这是一个贪心的过程,可以

POJ 2010 Moo University - Financial Aid( 优先队列+二分查找)

POJ 2010 Moo University - Financial Aid 题目大意,从C头申请读书的牛中选出N头,这N头牛的需要的额外学费之和不能超过F,并且要使得这N头牛的中位数最大.若不存在,则输出-1(一开始因为没看见这个,wa了几次). 这个题的第一种做法就是用两个优先队列+贪心. /* * Created: 2016年03月27日 14时41分47秒 星期日 * Author: Akrusher * */ #include <cstdio> #include <cstdl

BZOJ 3373: [Usaco2004 Mar]Lying Livestock 说谎的牲畜( 差分约束 )

枚举每头牛, 假设它在说谎, 建图判圈就行了...为啥水题都没人来写.. ------------------------------------------------------------------ #include<bits/stdc++.h> using namespace std; typedef pair<int, int> pii; const int maxn = 109; struct edge { int to, w; edge(int _t, int _w

poj 2010 Moo University - Financial Aid(优先队列(最小堆)+ 贪心 + 枚举)

Description Bessie noted that although humans have many universities they can attend, cows have none. To remedy this problem, she and her fellow cows formed a new university called The University of Wisconsin-Farmside,"Moo U" for short. Not wish

poj2010(Moo University - Financial Aid)优先队列

Description Bessie noted that although humans have many universities they can attend, cows have none. To remedy this problem, she and her fellow cows formed a new university called The University of Wisconsin-Farmside,"Moo U" for short. Not wish