當(dāng)前位置:
首頁(yè) >
完全背包之三
發(fā)布時(shí)間:2025/7/14
40
豆豆
//poj 3260 The Fewest Coins
/*
題意:John帶了n種幣值Vi的確定數(shù)量Ci的硬幣,而shopkeeper的硬幣無(wú)限多.
給出T,求John支付的硬幣數(shù)目加上售貨員找零的硬幣數(shù)目的最小值。如果無(wú)法支付T,輸出-1
支付時(shí)硬幣數(shù)量有限制,為多重背包問(wèn)題. 找零時(shí)硬幣數(shù)量無(wú)限制,為完全背包問(wèn)題
*/
#include<iostream> //多重背包和完全背包
using namespace std;
int main()
{
int n,t,euro[110],num[110],dp[30000],maxn;
cin>>n>>t;
int mx=0;
for(int i=1;i<=n;++i)
{
cin>>euro[i];
mx=max(mx,euro[i]);
}
maxn=mx*mx+t; //上界
for(int i=1;i<=n;++i)
cin>>num[i];
fill(dp,dp+maxn+1,-1);
dp[0]=0;
//John付錢(qián) 多重背包,通過(guò)二進(jìn)制方法轉(zhuǎn)化為01背包
for(int i=1;i<=n;++i)
{
int k=1,s=num[i];
while(s>=k)
{
for(int j=maxn;j>=euro[i]*k;--j)
if(dp[j-euro[i]*k]!=-1)
{
if(dp[j]==-1)
dp[j]=dp[j-euro[i]*k]+k; //注意是 +k
else
dp[j]=min(dp[j],dp[j-euro[i]*k]+k);
}
s-=k;k*=2;
}
for(int j=maxn;j>=euro[i]*s;--j)
if(dp[j-euro[i]*s]!=-1)
{
if(dp[j]==-1)
dp[j]=dp[j-euro[i]*s]+s;
else
dp[j]=min(dp[j],dp[j-euro[i]*s]+s);
}
}
//shopkeeper找錢(qián) 完全背包
for(int i=1;i<=n;++i)
{
for(int j=maxn-euro[i];j>0;--j) //因?yàn)槭菧p,所以要逆序循環(huán)
if(dp[j+euro[i]]!=-1)
{
if(dp[j]==-1)
dp[j]=dp[j+euro[i]]+1;
else
dp[j]=min(dp[j],dp[j+euro[i]]+1);
}
}
cout<<dp[t]<<endl;
return 0;
}
/*
上界為:T+maxValue^2,其中maxValue為最大硬幣面值。
證明:反證法。假設(shè)存在一種支付方案,John給的錢(qián)超過(guò)T+maxValue^2, 則售貨員找零超過(guò)maxValue^2,找的硬幣數(shù)目超過(guò)maxValue個(gè),將其看作一數(shù)列,求前n項(xiàng)和sum(n),
根據(jù)鴿巢原理,至少有兩 個(gè)對(duì)maxValue求模的值相等,假設(shè)為sum(i)和sum(j),i<j,則i+1...j的硬幣面值和為maxValue的倍數(shù),
同理,John給的錢(qián)中也有 一定數(shù)量的硬幣面值和為maxValue的倍數(shù),
則這兩堆硬幣可用數(shù)量更少的maxValue面值硬幣代替,產(chǎn)生更優(yōu)方案。
*/
/*
題意:John帶了n種幣值Vi的確定數(shù)量Ci的硬幣,而shopkeeper的硬幣無(wú)限多.
給出T,求John支付的硬幣數(shù)目加上售貨員找零的硬幣數(shù)目的最小值。如果無(wú)法支付T,輸出-1
支付時(shí)硬幣數(shù)量有限制,為多重背包問(wèn)題. 找零時(shí)硬幣數(shù)量無(wú)限制,為完全背包問(wèn)題
*/
#include<iostream> //多重背包和完全背包
using namespace std;
int main()
{
int n,t,euro[110],num[110],dp[30000],maxn;
cin>>n>>t;
int mx=0;
for(int i=1;i<=n;++i)
{
cin>>euro[i];
mx=max(mx,euro[i]);
}
maxn=mx*mx+t; //上界
for(int i=1;i<=n;++i)
cin>>num[i];
fill(dp,dp+maxn+1,-1);
dp[0]=0;
//John付錢(qián) 多重背包,通過(guò)二進(jìn)制方法轉(zhuǎn)化為01背包
for(int i=1;i<=n;++i)
{
int k=1,s=num[i];
while(s>=k)
{
for(int j=maxn;j>=euro[i]*k;--j)
if(dp[j-euro[i]*k]!=-1)
{
if(dp[j]==-1)
dp[j]=dp[j-euro[i]*k]+k; //注意是 +k
else
dp[j]=min(dp[j],dp[j-euro[i]*k]+k);
}
s-=k;k*=2;
}
for(int j=maxn;j>=euro[i]*s;--j)
if(dp[j-euro[i]*s]!=-1)
{
if(dp[j]==-1)
dp[j]=dp[j-euro[i]*s]+s;
else
dp[j]=min(dp[j],dp[j-euro[i]*s]+s);
}
}
//shopkeeper找錢(qián) 完全背包
for(int i=1;i<=n;++i)
{
for(int j=maxn-euro[i];j>0;--j) //因?yàn)槭菧p,所以要逆序循環(huán)
if(dp[j+euro[i]]!=-1)
{
if(dp[j]==-1)
dp[j]=dp[j+euro[i]]+1;
else
dp[j]=min(dp[j],dp[j+euro[i]]+1);
}
}
cout<<dp[t]<<endl;
return 0;
}
/*
上界為:T+maxValue^2,其中maxValue為最大硬幣面值。
證明:反證法。假設(shè)存在一種支付方案,John給的錢(qián)超過(guò)T+maxValue^2, 則售貨員找零超過(guò)maxValue^2,找的硬幣數(shù)目超過(guò)maxValue個(gè),將其看作一數(shù)列,求前n項(xiàng)和sum(n),
根據(jù)鴿巢原理,至少有兩 個(gè)對(duì)maxValue求模的值相等,假設(shè)為sum(i)和sum(j),i<j,則i+1...j的硬幣面值和為maxValue的倍數(shù),
同理,John給的錢(qián)中也有 一定數(shù)量的硬幣面值和為maxValue的倍數(shù),
則這兩堆硬幣可用數(shù)量更少的maxValue面值硬幣代替,產(chǎn)生更優(yōu)方案。
*/
轉(zhuǎn)載于:https://www.cnblogs.com/mjc467621163/archive/2011/08/23/2151020.html
總結(jié)
- 上一篇: Java读取、创建xml(通过dom方式
- 下一篇: chm文件无法正常显示