[USACO2.1]健康的荷斯坦奶牛 Healthy Holsteins

版权声明:虽然本蒟蒻很菜,但各位dalao转载请注明出处谢谢。 https://blog.csdn.net/xuxiayang/article/details/84670526

链接

洛谷
USACO


大意

给定 n n 种维生素的需求量,对于第 i i 种维生素的需求量,记为 a [ i ] a[i]

给定 m m 种饲料,对于第 i i 种饲料的第 j j 种维生素,其能增加 b [ i ] [ j ] b[i][j] 点维生素

问最少需要几个饲料,如果有多组解,输出最小的那个。

数据范围: n 25 , m 15 n\leq25,m\leq 15


思路

观察数据范围发现 m m 很小,于是我们可以 d f s dfs 或者状态压缩,本人用的是状态压缩。

我们状压 m m 个饲料的使用情况,然后进行判断,由于我们选择的顺序是从小到大的,所以自然字典序也是最小的,就不需要判断了。

判断使用了几种饲料的过程可以直接用循环判断,也可以用 l o w b i t lowbit 操作,两种判断方法的时间复杂度都是 O ( m ) O(m) l o w b i t lowbit 常数会小很多

总时间复杂度 O ( 2 m n m ) O(2^mnm)


代码

/*
ID:hzbismy1
LANG:C++
TASK:holstein
*/
#define file(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout)
#include<cstdio>
#include<cctype>
#include<cstring>
using namespace std;int n,a[36],b[25][25],m,ansk,ansi,k,s[25];
inline char Getchar()
{
    static char buf[100000],*p1=buf+100000,*pend=buf+100000;
    if(p1==pend)
	{
        p1=buf; pend=buf+fread(buf,1,100000,stdin);
        if (pend==p1) return -1;
    }
    return *p1++;
}
inline int read()
{
	char c;int d=1,f=0;
	while(c=Getchar(),!isdigit(c))if(c==45)d=-1;f=(f<<3)+(f<<1)+c-48;
	while(c=Getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
	return d*f;
}
inline void write(register long long x)
{
	if(x<0)write(45),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+48);
	return;
}//以上为读入输出优化
inline int getk(register int x)//获得x种1的个数
{
	int ans=0;
	while((x&-x)!=0)//lowbit操作
	{
		ans++;
		x-=x&-x;
	}
	return ans;
}
inline bool check()//判断能否满足需求
{
	for(register int i=1;i<=n;i++) if(s[i]<a[i]) return false;
	return true;
}
signed main()
{
	n=read();
	for(register int i=1;i<=n;i++) a[i]=read();
	m=read();ansk=m+1;//记得初始化
	for(register int i=1;i<=m;i++) for(register int j=1;j<=n;j++) b[i][j]=read();
	for(register int i=1;i<(1<<m);i++)
	{
		memset(s,0,sizeof(s));//记得清空
		for(register int j=0;j<m;j++)
		if((i>>j)&1) for(register int l=1;l<=n;l++) s[l]+=b[j+1][l];//如果选了则加上
		if(check())//合法
		{
			k=getk(i);
			if(k<ansk)//个数更少
			{
				ansi=i;
				ansk=k;
			}			
		}
	}
	write(ansk);for(register int i=0;i<m;i++) if((ansi>>i)&1) putchar(32),write(i+1);//输出
	putchar(10);//没有这行就会愉快的被USACO卡
}

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/84670526
今日推荐