解题报告饭卡

Posted sixwater6h2o

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了解题报告饭卡相关的知识,希望对你有一定的参考价值。

解题报告——饭卡

  • 问题描述   
Time Limit: 1000ms
Memory Limit: 32768KB
64-bit integer IO format: %I64d      Java class name: Main
电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额。如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负),否则无法购买(即使金额足够)。所以大家都希望尽量使卡上的余额最少。
某天,食堂中有n种菜出售,每种菜可购买一次。已知每种菜的价格以及卡上的余额,问最少可使卡上的余额为多少。
 

Input

多组数据。对于每组数据:
第一行为正整数n,表示菜的数量。n<=1000。
第二行包括n个正整数,表示每种菜的价格。价格不超过50。
第三行包括一个正整数m,表示卡上的余额。m<=1000。

n=0表示数据结束。
 

Output

对于每组输入,输出一行,包含一个整数,表示卡上可能的最小余额。

Sample Input

1
50
5
10
1 2 3 2 1 1 2 3 2 1
50
0

Sample Output

-45
32
  • 解题思路

    动态规划问题。解题的时候参考了01背包问题以及其延伸的小偷入户抢劫的问题,对于每一道菜都可以选择买或者不买,可以标记在选择购买这道菜之前能够到达的余额值,每次选择买或不买之后刷新能够达到的余额值,最后答案可以检索最小能够达到的余额值得到。

    其中为了保证余额最小,要保证价格贵的较后购买,所以要先对菜的价钱进行从小到大排序。

    并且为了使用数组进行标记,即要考虑余额为负的标记问题,把所有余额加上50进行标记,输出时用所求得答案减去50输出。

 

  • 错误代码

      最开始没有理解动态规划的含义,只是照着动态规划的感觉照葫芦画瓢还画错了。对于每一道菜都进行了选择并标记,事实上相当于从最便宜从最贵能买的都买了,并没有动态规划的状态转移过程。

 

      错误代码如下:

 

 1 //错的相当离谱的代码
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 int main()
 6 
 7     int n,m,i,x;
 8     while (1)
 9         scanf("%d",&n);
10         if (n==0) break;
11         int meal[n];
12         for (i=0;i<n;i++) scanf("%d",&meal[i]);
13         sort(meal,meal+n);
14         scanf("%d",&m);
15         x=m;
16         i=0;
17         int s[m+50];
18         for (i=0;i<m+49;i++) s[i]=0;
19         s[m+50]=1;
20         for (i=0;i<n;i++)
21             if (x>=5) 
22                 s[x+50-meal[i]]=1;//没有状态转移的过程,将每一道菜都选择了。
23                 x=x-meal[i];
24             
25         
26         for (i=0;i<m+50;i++)
27             if (s[i]==1)
28                 printf("%d\n",i-50);
29                 break;
30             
31     
32     return 0;
33 

 

  • AC代码

   又看了看关于动态规划问题,重点学习了一下01背包问题延伸的小偷入户抢劫问题,找到了这道题的转移方程,即

 

1     for (i=0;i<n;i++)
2         for (j=55;j<=m+50;j++)
3             if (s[j]==1)
4                 s[j-meal[i]]=1;
5             
6         
7     

      利用上一次能达到的所有余额值来更新选择了这道菜后能达到的余额值,这样再选择所有能达到余额值的最小值就能得到答案。

      AC代码如下:

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 int main()
 5 
 6     int n,m,i,j,x,ans;
 7     while (1)
 8         scanf("%d",&n);
 9         if (n==0) break;
10         int meal[n];
11         for (i=0;i<n;i++) scanf("%d",&meal[i]);
12         sort(meal,meal+n);
13         scanf("%d",&m);
14         x=m;
15         i=0;
16         int s[m+51];
17         for (i=0;i<=m+49;i++) s[i]=0;
18         s[m+50]=1;
19         ans=m+50;
20         for (i=0;i<n;i++)
21             for (j=55;j<=m+50;j++)
22                 if (s[j]==1)
23                     s[j-meal[i]]=1;
24                     ans=min(ans,j-meal[i]);
25                 
26             
27         
28         printf("%d\n",ans-50);
29     
30     return 0;
31 

题是简单题,但架不住我菜啊(。)

以上是关于解题报告饭卡的主要内容,如果未能解决你的问题,请参考以下文章

解题报告力扣 第 285 场周赛

解题报告力扣 第 268 场周赛

解题报告力扣 第 271 场周赛

解题报告力扣 第 263 场周赛

解题报告力扣 第 269 场周赛

解题报告力扣 第 288 场周赛