usaco Healthy Holsteins

这题拖了很久,一开始想用dfs结果写不出来,然后在网上看到应该枚举而且又看到这种状态压缩枚举算学到东西了,接着又看到用bfs的。

/*
ID: nanke691
LANG: C++
TASK: holstein
*/
#include<iostream>
#include<fstream>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
struct node
{
    int state;//用位来记录路径,即使用过哪几种饲料
    int ver[26];//保存状态值,
    short cur;//当前选择的编号最大的饲料
    short cnt;//已选择的种类数
};
int hol[20][30];
int V,G,aim[30],len,ans;
queue<node> Q;
bool  compare(int *a)//判断是否符合条件
{
    for(int i=1;i<=V;i++)
        if(a[i]<aim[i])
            return false;
    return true;
}
void BFS()
{
    node s,f;
    for(int i=1;i<=G;i++)
    {
        for(int j=1;j<=V;j++)
            s.ver[j]=hol[i][j];
        s.state=(1<<(i-1));
        s.cur=i;
        s.cnt=1;
        Q.push(s);
    }
    len=100000000;
    while(!Q.empty())
    {
        f=Q.front();
        Q.pop();
        if(f.cnt<=len && compare(f.ver))
        {
 
            len=f.cnt;  
            ans=f.state;
            break;
        }
        for(int i=f.cur+1;i<=G;i++)
        {
            for(int j=1;j<=V;j++)
                s.ver[j]=f.ver[j]+hol[i][j];
            s.cnt=f.cnt+1;
            s.cur=i;
            s.state=(f.state | (1<<(i-1)));//记录下当前选取的编号
            Q.push(s);
        }
    }
}
int main()
{
    freopen("holstein.in","r",stdin);
    freopen("holstein.out","w",stdout);
    scanf("%d",&V);
    for(int i=1;i<=V;i++)
        scanf("%d",&aim[i]);
    scanf("%d",&G);
    for(int i=1;i<=G;i++)
        for(int j=1;j<=V;j++)
            scanf("%d",&hol[i][j]);
    BFS();
    cout<<len<<' ';
    int flag=0;
    for(int i=1;i<=G;i++)
    {
        if((ans &(1<<(i-1)))!=0)
        {
            if(!flag)
            cout<<i,flag=1;
            else cout<<' '<<i;
        }
    }
    cout<<endl;
}


第二种方法就是简单的bfs不过他记录路径的方法很巧妙,学习了。代码直接搬过来了

/*
ID :jinbo wu
LANG: C++
TASK:holstein
*/
#include<bits/stdc++.h>
using namespace std;
int a[30];
int b[20][30];
int ans[25];
int t[25];
int sum,mark,flag,cnt;
int main()
{
	freopen("holstein.in","r",stdin);
	freopen("holstein.out","w",stdout);
	int n,l;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	scanf("%d",&a[i]);
	int g;
    scanf("%d",&g);
    for(int i=0;i<g;i++)
    {
    	for(int j=0;j<n;j++)
    	scanf("%d",&b[i][j]);
	}
	int maxn=1<<g;
	sum=maxn;
	for(int i=1;i<=maxn;i++)
	{
		flag=0;
		cnt=0;
		int temp=i;
		while(temp)
		{
			if(temp&1) cnt++;
			if(cnt>=sum)
			{
				flag=1;
				break;
			}
			temp>>=1;
		}
		if(flag)
		continue;
		temp=i;
		 l=0;
		memset(t,0,sizeof(t));
		while(temp)
		{
			if(temp&1)
			{
			 for(int j=0;j<n;j++)
			 t[j]+=b[l][j];
		    }
			 temp>>=1;
	    	 l++;
	        
		}
		for(int j=0;j<n;j++)
		{
			if(t[j]<a[j])
			{
				flag=1;
				break;
			}
		}
		if(flag==0)
		{
		 sum=cnt;
		 mark=i;
	    }
	}
	printf("%d",sum);
	l=1;
	while(mark)
	{
		if(mark&1)
		printf(" %d",l);
		mark>>=1;
		l++;
	}
	printf("\n");
}
第二种方法就是简单的bfs不过他记录路径的方法很巧妙,学习了。代码直接搬过来了



第二种方法就是简单的bfs不过他记录路径的方法很巧妙,学习了。代码直接搬过来了
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值