P2036 [COCI2008-2009#2] PERKET

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

思路:
第一次接触从n个物品里选择一部分物品的题目,刚开始有点不知所措,所以先找了一些思路与想法作为参考来完成自己的代码
1.法一:
对于调料的状态有两种选择,选或者不选
第一种代码就是针对这种思路去写的

#include <cstdio>
#include <iostream>
#include <cmath>
using namespace std;
long long n;
long long a[11],b[11],ans;
void dfs(long long cnt,long long x,long long y)
{
	if(cnt>n)
	{
		if(x==1&&y==0) return;
		ans=min(ans,abs(x-y));//cout<<ans<<endl;
		return;
	} 
	dfs(cnt+1,x*a[cnt],b[cnt]+y);
	dfs(cnt+1,x,y);
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i]>>b[i];
	ans=abs(b[1]-a[1]);//cout<<ans<<endl;
	dfs(1,1,0);
	cout<<ans<<endl;
	return 0;
}

2.法二:
要选择n个物品中的部分商品
这里的q+1表示的是后面选择的一定在数列中位于前面选择的后面的位置,可以避免重复的情况

#include <cstdio>
#include <iostream>
#include <cmath>
using namespace std;
int n,m,a[11],b[11],vis[100];
long long ans=0x3f3f3f3f;
long long now1=1,now2=0;
void dfs(int m,int q)
{
	//for(int i=1;i<=n;i++) cout<<vis[i]<<" ";
	//cout<<endl;
	if(m!=1) ans=min(ans,abs(now1-now2));
	for(int i=q+1;i<=n;i++)
	{
		if(!vis[i])
		{
			now1*=a[i];
			now2+=b[i];
			vis[i]=true;
			dfs(m+1,i);
			vis[i]=false;
			now1/=a[i];
			now2-=b[i];
		}
	}
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i]>>b[i];
	dfs(1,0);
	
	cout<<ans<<endl;
	return 0;
}

3.特殊方法:
借用二进制来表示这个数是否被选择,适用于物品的有且只有两种状态(在这道题目中为是否被选择)并且最终答案与物品的顺序无关
写法一:

#include <cstdio>
#include <iostream>
#include <cmath>
using namespace std;
int n,a[11],b[11];
long long ans=0x3f3f3f3f;
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i]>>b[i];
	//cout<<ans<<endl;
	for(int i=1;i<(1<<n);i++)
	{
		long long now1=1,now2=0;
		for(int j=0;j<n;j++)
		{
			if((i>>j)&1==1) 
			{
				now1*=a[j+1];//cout<<now1;
				now2+=b[j+1];//cout<<now2;
			}
		}	
		//cout<<ans<<endl;
		ans=min(ans,abs(now1-now2));
	}
	cout<<ans<<endl;
	return 0;
}

写法二:

#include <cstdio>
#include <iostream>
using namespace std;
const int maxn=11;
int how_many_in_total,deciding_which_object,s[maxn],b[maxn];
long long suandu,kudu,answer=0x3f3f3f3f;
bool first_try=true;
void dfs(int deciding_which_object)
{
	if (deciding_which_object==how_many_in_total+1) 
	{
		if (first_try)
		{
			first_try=false;
			return;
		}
		answer=min(answer,abs(suandu-kudu));
		return;
	}
	dfs(deciding_which_object+1);
	suandu*=s[deciding_which_object];
	kudu+=b[deciding_which_object];
	dfs(deciding_which_object+1);
	suandu/=s[deciding_which_object];
	kudu-=b[deciding_which_object];
}
int main()
{
	cin>>how_many_in_total;
	for (int i=1;i<=how_many_in_total;i++) scanf("%d%d",s+i,b+i);
	suandu=1;
	dfs(1);
	cout<<answer<<endl;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值