1. 程式人生 > >codeforces 913C Party Lemonade (貪心 + DFS)

codeforces 913C Party Lemonade (貪心 + DFS)

題目大意:

有 n 種檸檬汁,第 i 種每瓶的容量為 2^(i-1) 升,價格為 Ci,問至少買 L 升檸檬汁最少花多少錢?

思路:

一看題,第一感覺是 DP,但是由於購買數可以超過 L 升,並且 L 太大了,所以不能用 DP解決。我們採取貪心的策略:優先買單價更低的。這樣會出現一個問題,剩餘量如果不夠一瓶,我們是買一瓶單價最低的呢?還是從單價更高的中拼一下呢?因為買一瓶單價最低的話會產生一點浪費。所以我們就可以按照這個思路用 DFS做。

程式碼:

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;

LL n,mn;

struct node
{
	LL cost,lit; //每瓶的價格和容量 
	double v; //單價 /升 
} a[33];

LL cmp(node a,node b)
{
	return a.v<b.v;
}

void dfs(LL dep,LL res,LL ans)
{ //引數:當前位置,剩餘量,當前花費 
	int f=0;
	if(ans>=mn) return; //如果當前花費比最小值大則退出 
	if(dep==n||res<=0)
	{ //如果搜尋完畢或者已經購買完,則更新最小值並退出 
		if(ans<mn) mn=ans;
		return;
	}
	LL x=res/a[dep].lit; //當前種檸檬汁可以買多少瓶 
	if(res%a[dep].lit!=0)
	{ //如果剩餘不夠一瓶,則多買一瓶 
		x++;
		f=1;
	}
	ans+=x*a[dep].cost; //先多買一瓶當前種的 
	res-=x*a[dep].lit;
	dfs(dep+1,res,ans);
	if(f==1)
	{ //如果多買了,則在回溯時還原 
		ans-=a[dep].cost;
		res+=a[dep].lit;
		dfs(dep+1,res,ans);
	}	
}

int main()
{
	LL i,l;
	while(~scanf("%lld%lld",&n,&l))
	{
		for(i=0;i<n;i++)
		{
			scanf("%lld",&a[i].cost);
			a[i].lit=1<<i;
			a[i].v=(double)a[i].cost/a[i].lit;
		}
		sort(a,a+n,cmp); //按單價升序排序 
		mn=0x7fffffffffffffff;
		dfs(0,l,0);
		printf("%lld\n",mn);
	}
	return 0;
}