BZOJ 3371 POJ 2009 : [Usaco2004 Mar]Moo University - Emergency Pizza Order 定制比萨饼 状压DP+匈牙利算法

版权声明:https://blog.csdn.net/huashuimu2003 https://blog.csdn.net/huashuimu2003/article/details/89321332

title

BZOJ 3371
POJ 2009
LUOGU SP3679
JYOJ 1389
Description

Moo U’s cafeteria has run out of hay and so must order pizzas for the C (1 <= C <= 1,000) calves attending Moo U. Conveniently, a large pizza from the local pizzeria, Pizza Farm, serves exactly one calf.
Pizza Farm is willing to make a pizza for each calf, but, due to the size of the order, has three constraints on the order:

  • Although Pizza Farm has long list of T (1 <= T <= 30) vegetarian toppings, each of the pizzas must have exactly K (1 <= K <=T) toppings
  • No topping on a pizza can be duplicated (a pizza cannot have onions and onions, for example).
  • No two pizzas in the order can have the same set of toppings.For example, if pizza 1 has onions, green peppers, pineapples, and wheat grass, then it can be the only pizza with that exact set of toppings, although pizza 2 might have onions, green peppers, pineapples, and also olives.For ordering purposes, the toppings are numbered 1…T.
    The calves at Moo U are very picky when it comes to their pizza toppings. Some calves might not like all of the toppings available.
    A calf will eat a pizza only she likes every single one of the toppings on that pizza. Determine the maximum number of calves that can be fed.

Input

  • Line 1: Three integers: C, T, and K.
  • Lines 2…C+1: Each line of space-separated integers describes which toppings one of the calves likes. The first integer on a line is the number of topping the calf likes. The remaining integers on the line are the toppings that the calf likes.

Output

  • Line 1: A single integer, the maximum number of calves that can be fed.

Sample Input

3 2 1
2 2 1
1 1
1 2

Sample Output

2

Hint

Sample input:There are three calves. Pizza Farm has two toppings and each pizza must have exactly one topping. The first calf likes both of the toppings, the second calf likes only the first topping, and the third calf likes only the second topping.
Sample output:There are only two pizzas that can be made: a pizza with topping 1 and a pizza with topping 2. If the first pizza is given to the first calf (since she likes topping 1) and the second pizza to the third calf (since she likes topping 2), two calves will be fed.
There is no way to feed all three calves.

Source

USACO 2004 March Green

translate

Description

Moo大学的餐厅必须为C(1≤C≤1000)头入学的奶牛新生定制比萨饼.比萨饼可以在比萨小屋订做.一个饼只能给一头奶牛吃.尽管比萨小屋想为每一头奶牛都做一个比萨饼,但是他们必须服从以下三个条件:
·比萨小屋拥有T(1≤T≤30)种素菜馅,每个比萨饼有且仅有K(1≤K≤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号牛,这样两头牛被喂饱了.同时将三头都喂饱的办法不存在

Source

Green

analysis

一边匹配一边加点,先加点,如果不能加了就用匈牙利调整。

有几个剪枝,就是 &lt; k &lt;k 的牛不用管了,然后记住吃不到的牛,下次包含于这个搭配的其他牛也一定失败。

code

#include<bits/stdc++.h>
using namespace std;
const int maxc=1100,maxm=40,maxn=111117;
template<typename T>inline void read(T &x)
{
	x=0;
	T f=1, ch=getchar();
	while (!isdigit(ch) && ch^'-') ch=getchar();
	if (ch=='-') f=-1, ch=getchar();
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
	x*=f;
}
int cow[maxc][maxm];//cow[i][j]表示第i头cow所喜欢的的第j种馅
int hash[maxn],cnts[maxc],piz[maxc];
inline int query(int k)
{
	int p=k%maxn;
	while (hash[p] && hash[p]!=k)
		p=(p+10)%maxn;
	return p;
}

inline bool hashit(int k)
{
	int p=k%maxn;
	while (hash[p] && hash[p]!=k)
		p=(p+10)%maxn;
	if (!hash[p]) hash[p]=k;
	else return false;
	return true;
}

inline int dfs(int x);

int c,t,k;
int match[maxn],vis[maxn];
int fail[maxn],top,ans;
inline int coordinate(int x,int cnt,int id,int pz)//当前x号牛,现在已经用了cnt种馅,要用第id种馅
{
	if (cnts[x]-id+cnt<k) return 0;
	if (cnt==k)
	{
		int p=query(pz);
		if (vis[p]) return 0;
		vis[p]=1;
		if (!match[p] || dfs(match[p]))
		{
			match[p]=x;
			return 1;
		}
		return 0;
	}
	else
	{
		if (coordinate(x,cnt,id+1,pz)) return 1;
		else
		{
			pz|=1<<cow[x][id]-1;
			if (coordinate(x,cnt+1,id+1,pz)) return 1;
			return 0;
		}
	}
	return 0;
}

inline int NewPiz(int x,int cnt,int id,int pz)//同上
{
	if (cnts[x]-id+cnt<k) return 0;
	if (cnt==k)
	{
		if (!hashit(pz)) return 0;
		int p=query(pz);
		match[p]=x;
		return 1;
	}
	else
	{
		if (NewPiz(x,cnt,id+1,pz)) return 1;
		else
		{
			pz|=1<<cow[x][id]-1;
			if (NewPiz(x,cnt+1,id+1,pz)) return 1;
			return 0;
		}
	}
	return 0;
}

inline int dfs(int x)
{
	if (cnts[x]<k) return 0;
	for (int i=0; i<top; ++i)
		if (!(piz[x]&(~fail[i])))
			return 0;
	if (NewPiz(x,0,0,0)) return 1;
	else if (coordinate(x,0,0,0)) return 1;
	else fail[top++]=piz[x];
	return 0;
}

int main()
{
	while (~scanf("%d %d %d",&c,&t,&k))
	{
		for (int i=1; i<=c; ++i)
		{
			piz[i]=0;
			read(cnts[i]);
			for (int j=0; j<cnts[i]; ++j)
			{
				read(cow[i][j]);
				piz[i]|=1<<cow[i][j]-1;//建造每个状态的合法转移条件
			}
		}
		top=ans=0;
		memset(hash,0,sizeof(hash));
		memset(match,0,sizeof(match));
		for (int i=1; i<=c; ++i)
		{
			memset(vis,0,sizeof(vis));
			if (dfs(i)) ++ans;
		}
		printf("%d\n",ans);
	}
	return 0;
}

summary

看了半天,也不知道该怎样状压,最后崩溃,决定找题解,然而发现网上题解少得可怜,

C l a r i s Claris 大爷的 b l o g blog 找了半天没找到,最后竟然还是找到了一篇,题解就俩行就是上面的题解

很无语,就看代码,最后看懂了,然后发现这俩行题解,其实挺能说明这道题的关键点的,前提是

状压DP的一些基本技能都清楚,后来发现这道题还有个错误?的贪心算法,不会写,跳过!然后去

写下一题!

猜你喜欢

转载自blog.csdn.net/huashuimu2003/article/details/89321332