/*
题意:
有各种不同面值的货币,每种面值的货币有不同的数量,请找出利用这些
货币可以凑成的最接近且小于等于给定的数字cash的金额。
思路:
多重背包(01背包,完全背包,多重背包(2进制原理)2种背包的转换
dp[i]表示能用所给硬币凑到最接近i的数目
*/
#include<iostream>
using namespace std;
const int MAXN=100005;
int mymax(int a,int b)
{
return a>b?a:b;
}
struct Node
{
int n;//硬币个数
int d;//硬币面值
};
Node coins[15];//数据录入
int dp[MAXN];//dp[i]表示能用所给硬币凑到最接近i的数目
//当dp[i]==i时,表示刚好可以用所给硬币凑到数目i
//并且dp[i]一定小于等于i
void CompletePack(int w,int m) //完全背包(顺序求解,w即使重量也是价值)
{
for(int i=w;i<=m;i++)
{
dp[i]=mymax(dp[i],dp[i-w]+w);
}
}
void ZeroOnePack(int w,int m) //01背包(逆序求解,w即使重量也是价值)
{
for(int i=m;i>=w;i--)
{
dp[i]=mymax(dp[i],dp[i-w]+w);
}
}
void MuiltPack(int w,int c,int m)//
{
if(w*c>=m)//面值*数目〉所要凑得面值(相当于有无限多个面值为w的硬币可用)
{
CompletePack(w,m);//多重背包-->完全背包
}
else//否则,多重背包-->01背包
{ //二进制原理转换成01背包求解。
int k=1;//k从1.2.4.....
while(c-k>0)
{
ZeroOnePack(w*k,m);
c-=k;
k*=2;
}
ZeroOnePack(w*c,m);//剩下的硬币数目
}
}
int main()
{
int cash,N;//所给要求的面值和硬币数量
while(cin>>cash>>N)
{
memset(dp,0,sizeof(dp));//初始化
for(int i=1;i<=N;i++)//数据录入
{
cin>>coins[i].n; //硬币个数
cin>>coins[i].d; //硬币价值
}
if(!cash||!N)//只要有一个为0,则答案就是0
{
cout<<0<<endl;
continue;
}
for(int i=1;i<=N;i++)
{
MuiltPack(coins[i].d,coins[i].n,cash);
}
cout<<dp[cash]<<endl;
}
return 0;
}