您的位置:首页 > 其它

背包——变向背包(hdu2546,1114,1203,2189)

2016-11-20 13:33 169 查看
*本篇讲述一些可以根据背包的思路解决的一些例题。

如对01背包、多重背包、完全背包等不理解的同学请参考前几篇博客~

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=2546

题目描述:

电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额。如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负),否则无法购买(即使金额足够)。所以大家都希望尽量使卡上的余额最少。

某天,食堂中有n种菜出售,每种菜可购买一次。已知每种菜的价格以及卡上的余额,问最少可使卡上的余额为多少。

/*变向01背包,因为卡上钱数大于5就可以买东西,题目要求是钱花的越多越好,
所以先将最贵的留到最后当钱数为5的时候去购买,
那么就变成了v=余额m-5的01背包问题*/

#include<stdio.h>
int a[1010][1010];

int fmax(int a,int b)
{
return a>b?a:b;
}

int main()
{

int i,j,n,m,t;
int b[1010];

while(~scanf("%d",&n),n)
{
a[0][0]=0;
i=1;j=1;
for(i=1;i<=n;i++)
scanf("%d",&b[i]);
scanf("%d",&m);

for(i=1;i<n;i++)     //b[i+1]为最贵的菜,等到最后买。
if(b[i]>b[i+1])
{
t=b[i];b[i]=b[i+1];b[i+1]=t;
}

for(i=1;i<n;i++)     //这里i<n而不是i<=n,因为不算最贵的菜
for(j=0;j<=m-5;j++)    //先腾出5元的空间留着买最贵的
{
if(j-b[i]>=0)       //01背包
a[i][j]=fmax(a[i-1][j],a[i-1][j-b[i]]+b[i]);
else
a[i][j]=a[i-1][j];
}
if(m>=5)     //如果m的值大于5,才能买菜扣钱,否则不能买菜,m等于本身
m=m-a[i-1][j-1]-b
;

printf("%d\n",m);
}
return 0;
}


题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=1114

题目描述:

给出小猪钱罐的重量和装满钱后的重量,然后是几组数据,每组数据包括每种钱币的价值与重量,要求出重量最少能装满钱罐时的最大价值

/*标准完全背包,只不过求的是存钱罐里最少的钱数
只要把max改成min就可以,完全背包就是每种物品可以取无数次
这样对于每一个物品,他的最高价值都没有尽头,所以只能用完全取代
来做*/

#include<stdio.h>
int min(int a,int b)
{
return a>b?b:a;
}
int main()
{
int t,e,f,n,v;
int p[10000],w[10000],dp[10000];
int i,j;
int max=99999999;         //自定义最大值
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&e,&f);
v=f-e;                   //v为容量
sca
4000
nf("%d",&n);
for(i=0;i<n;i++)
scanf("%d%d",&p[i],&w[i]);
for(i=1;i<=v;i++)
dp[i]=max;                   //因为最小解是最优解,所以初始都要变成最大值

for(i=0;i<n;i++)            //外层循环仍然是数量n
for(j=w[i];j<=v;j++)         //内层循环仍然是重量v
dp[j]=min(dp[j],dp[j-w[i]]+p[i]);   //当第一个物品进入时,dp[j]就进行优质取代
//每到一个可以减去一个w[i]时,就会判断是否选择用状态转移方程,当第i个物品进入时,
//还是用这个数组依次进行优质取代判断,所以这里是一维数组,但是时间方面会更耗费

if(dp[v]==max)                 //如果等于max,那么就是一个没有改变过的空间,那么是不可能存在的
printf("This is impossible.\n");
else
printf("The minimum amount of money in the piggy-bank is %d.\n",dp[v]);

}
return 0;

}


题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=1203

题目描述:

Speakless很早就想出国,现在他已经考完了所有需要的考试,准备了所有要准备的材料,于是,便需要去申请学校了。要申请国外的任何大学,你都要交纳一定的申请费用,这可是很惊人的。Speakless没有多少钱,总共只攒了n万美元。他将在m个学校中选择若干的(当然要在他的经济承受范围内)。每个学校都有不同的申请费用a(万美元),并且Speakless估计了他得到这个学校offer的可能性b。不同学校之间是否得到offer不会互相影响。“I NEED A OFFER”,他大叫一声。帮帮这个可怜的人吧,帮助他计算一下,他可以收到至少一份offer的最大概率。(如果Speakless选择了多个学校,得到任意一个学校的offer都可以)。

/*变向01背包,因为被选中的概率有很多种情况,所以先算他没被选中的概率,再减,
这样就是求最小价值的背包问题了*/

#include<stdio.h>
double dp[1020][1020];
double fmin(double a,double b)
{
return a<b?a:b;
}
int main()
{
double b[1020];
int a[1020];
int i,m;
int n,j;

while(~scanf("%d%d",&n,&m))
{
if(n==0&&m==0)
break;
for(i=1;i<=m;i++)
{
scanf("%d%lf",&a[i],&b[i]);
b[i]=1.0-b[i];            //把选上的概率变成没被选上的概率
}
for(i=0;i<=n;i++)
dp[0][i]=1;                 //如果没申请的话没被选上的概率是100%,也就是1
for(i=1;i<=m;i++)
{
for(j=0;j<=n;j++)
{
if(j-a[i]>=0)
dp[i][j]=fmin(dp[i-1][j],dp[i-1][j-a[i]]*b[i]);//状态转移方程,概率是相乘的关系
else
dp[i][j]=dp[i-1][j];
}

}
dp[m]
=1-dp[m]
; //dp[m]
是没被选上的最小值,用1减去也就是选上的最大值了
dp[m]
*=100;
printf("%.1lf%%\n",dp[m]
);
}
return 0;
}


题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=2189

题目描述:

灾区来了n位志愿者,抗震救灾指挥部需要将他们分为若干个小组,小组的数量不限,但是要求每个小组的人数必须为素数,请问我们有几种分组的方法呢?

#include<stdio.h>
#include<math.h>
#include<string.h>
int a[160];
void sushu()              //打表素数
{
int i,j;
for(i=2;i<=150;i++)
for(j=2;j<=sqrt(i);j++)
if(i%j==0)
{
a[i]=1;
continue;
}
//for(i=2;i<=150;i++)
//if(!a[i])
//printf("%d~~~",i);
}

int dp[160];
void fdp()               //打表dp
{
/*采用完全背包的思想,把质数看作物品,150看作容纳量

*/
memset(dp,0,sizeof(dp));
int i,j;
dp[0]=1;                  //当i物品是质数本身时需+1,故dp[0]=1
for(i=2;i<=150;i++)       //外层循环物品
if(!a[i])                 //如果为质数进行循环赋值
for(j=0;j+i<=150;j++)     //内层循环容纳量
dp[j+i]+=dp[j];           //这里用DP叠加可选择的方案数

}
int main()
{
int c,n;
sushu();
fdp();
scanf("%d",&c);
while(c--)
{
scanf("%d",&n);
printf("%d\n",dp
);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: