codechef Mike and Stamps

本文介绍了一个邮票销售问题的解决方法,旨在帮助一位收藏家最大化其邮票销售收益。面对有限数量的邮票和多个买家的不同需求,文章提供了一种通过递归枚举并适当剪枝的方法来确定最优的邮票销售方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

All submissions for this problem are available.

Read problems statements in Mandarin Chinese and Russian.

Mike is fond of collecting stamps. He has a lot of rare and unusual ones in his collection. Unfortunately, a few days ago he was fired from his well-paid job.

But he doesn't complain about that, he acts! That's why Mike picked up N stamps from his collection and is going to sell them. He has already placed an announcement on the Internet and got M offers. Each offer can be described as a set of stamps, that the buyer wants to buy. Now Mike needs your help to choose a set of offers, that he should accept.

He can't accept offers partially. Also, as far as Mike has the only copy of each stamp, he can sell one stamp to at most one buyer.

Of course, Mike wants to maximize the number of accepted offers. Help him!

Input

The first line contains two integer N and M, denoting the number of the stamps and the number of the offers.

The next M lines contain the descriptions of the offers. The (i+1)'th line of the input contains the description of the i'th offer and corresponds to the following pattern: Ki Ai, 1 Ai, 2, ..., Ai, KiKi - is the number of the stamps, which the i'th buyer wants to buy, Ai - is the list of the stamps sorted in the ascending order.

 

Output

Output should contain the only integer, denoting the maximal number of the offers, that Mike can accept.

 

Constraints

1 ≤ N ≤ 20,000

1 ≤ M ≤ 20

1 ≤ Ki

 

Example

Input:
4 3
2 1 2
2 2 3
2 3 4

Output:
2

 

Explanation

In the example test Mike should accept the first and the third offer.


今天重做了一下codechef以前的错题。。结果发现自己真的不在状态。。

题意:有n张邮票卖。但是顾客可能一次要几张。。

问你最多可以卖给多少个顾客。每种邮票只有一张。

题解:首先看到顾客最多只有20个。所以就算是枚举也只是2^20 100w

不会超时。而且首先是计算出每两个顾客是否冲突。

然后就递归枚举。。加少量的剪枝。。

但是递归更新最大值时wa了很多次。后来才发现有一种情况没更新。。。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
int stamp[22][20002];
int xy[22][22];
int num[22],n,m,ans,f[22];
int max(int a,int b) {
	return a>b?a:b;
}
int ok(int k,int p) {
	int i,j = 0;
	for(i=0;i<num[k] && j<num[p];) {
		if(stamp[k][i]==stamp[p][j]) return 0;
		else if(stamp[k][i]>stamp[p][j]) j++;
		else i++;
	}
	return 1;
}
void make() {
	int i,j;
	for(i=0;i<m-1;i++)
	for(j=i+1;j<m;j++)
	xy[i][j] = xy[j][i] = ok(i,j);
}
bool work(int p,int a[],int len) {
	int i;
	for(i=0;i<len;i++) {
		if(xy[a[i]][p]==0)
		return 0;
	}
	return 1;
}
void DFS(int p,int len,int a[]) {
	int i;
	
	if(p>=m) {
	ans = max(ans,len);
	return ;
	}
	for(i=p;i<m;i++) {
		if(f[i]==0 && work(i,a,len)) {
			f[i] = 1;
			a[len] = i;
			DFS(i+1,len+1,a);
			f[i] = 0; 
		}
	}
	ans = max(ans,len);  //递归是忘记了最后一个不可以选择时就进不了return这个语句。然后就更新不了最大值
}						//为什么要犯这种错误。。。。
int main()
{
    int i,j,p;
    int a[22];
    scanf("%d%d",&n,&m);
    for(i=0;i<m;i++) {
    	scanf("%d",&num[i]);
    	for(j=0;j<num[i];j++)
    	scanf("%d",&stamp[i][j]);
    }

    make();
    ans = 1;
    DFS(0,0,a);
     printf("%d\n",ans);
    return 0;  
}    




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值