ZOJ 3305 Get Sauce(DFS+剪枝)

37 篇文章 1 订阅

首先对方式按照材料分类.

然后排序再搜索,详细的看注释.

跑了1.9秒多,可能还有其他的剪枝吧.

#include <iostream>
#include <memory.h>
#include <cstdio>
#include <memory.h>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn=17;

vector<int>v1[maxn];//需要这种材料的方式
vector<int>v2[50010];//这种方式需要的材料
bool vis[maxn],vis2[50010][17];
int n,m,ans;
bool cmp(const int a,const int b ){
	return v2[a].size()<v2[b].size();
}
void dfs(int mLeft,int cnt){
	if(cnt>ans){
		ans=cnt;
	}else if(mLeft+cnt<ans||!mLeft)return;//剩下的材料就算一个材料一瓶也比当前最优值小,剪掉
	int i=0;
	for (i=1;i<=n&&vis[i];++i);//找到没有被选掉的第一个材料
	if(i>n)return;
	for (int j=0;j<v1[i].size();++j){//遍历这个需要这个材料的所有方式
			vector<int> &v=v2[v1[i][j]];
			if(v.size()>mLeft)return;//因为已经排过序所以如果需要的材料数量大于剩余材料数,剪掉
			int f=0;
			for (int k=1;k<=n;++k){//判断这种方式需要的材料是否已经被选了
				if(vis[k]&&vis2[v1[i][j]][k]){
					f=1;
					break;
				}
			}
			if(!f){
				for (int k=0;k<v2[v1[i][j]].size();++k){//把这种方式需要的材料选掉
					vis[v[k]]=1;
				}
				dfs(mLeft-v2[v1[i][j]].size(),cnt+1);
				for (int k=0;k<v2[v1[i][j]].size();++k){//还原
					vis[v[k]]=0;
				}
			}
	}
}
int main(){
	while (scanf("%d%d",&n,&m)==2){
		for (int i=0;i<n;++i){
			v1[i].clear();
		}
		for (int i=0;i<m;++i){
			v2[i].clear();
			memset(vis2[i],0,sizeof(vis2[i]));
		}
		for (int i=0;i<m;++i){
			int size;
			scanf("%d",&size);
			while (size--){
				int t;
				scanf("%d",&t);
				v2[i].push_back(t);
				v1[t].push_back(i);
				vis2[i][t]=1;
			}
		}
		for (int i=0;i<n;++i){
			sort(v1[i].begin(),v1[i].end(),cmp);
		}
		ans=0;
		dfs(n,0);
		printf("%d\n",ans);
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值