【发布时间】:2014-05-18 06:36:13
【问题描述】:
问题:
考试由 N 个问题组成。 N道题的分数分别为m1、m2、m3、.. mN。 Jam 正在参加考试,他想最大限度地提高自己的分数。 然而,他需要一些时间来解决每个问题。他解决问题所用的时间分别为 t1, t2, t3, .. tN。 考试总时间为T。 但是 Jam 的老师很聪明,她知道 Jam 会想办法获得最高分。所以,为了迷惑Jam,她还为他提供了奖金—— 提议是,Jam 可以选择一个问题,他可以为该问题获得双倍的分数。 现在,Jam 确实很困惑。帮助他找出他可以获得的最大分数。
约束
1
1
1
1
我尝试了这个问题here 并提出了以下算法:
既然问题说,我们可以选择一个问题,他可以为该问题获得双倍的分数。
所以,为了选择那个问题,我应用了贪婪方法,即..
- 应选择具有较大(分数/时间)比率的问题,他可以为此问题获得双倍分数。
-
如果该比例也相同,则应选择分数较大的问题。
就我理解的问题而言,其余的都是简单的背包。 我尝试了以下实现,但得到了错误的答案。 对于给定的测试用例,我的代码给出了正确的输出
3 10 1 2 3 4 3 4
我已经尝试了 cmets 部分中给出的这个测试用例,我的代码给出了 16 作为输出,但答案应该是 18
3
9
9 6 5
8 5 3
蛮力方法会超出时间限制,因为解决 N 个背包的复杂度 O(nW) 将给出 O(n^2 W) 的整体时间复杂度 我认为可以为这个问题开发一个更具体的算法。 还有比这更好的主意吗?
谢谢
#include<iostream>
#include<cstdio>
using namespace std;
int T[2][10002];
int a[1000002],b[100002];
float c[100002];
int knapSack(int W,int val[],int wgt[],int n)
{
int i,j;
for(i=0;i<n+1;i++)
{
if(i%2==0)
{
for(j=0;j<W+1;j++)
{
if(i==0 || j==0)
T[0][j]=0;
else if(wgt[i-1]<=j)
T[0][j]=max(val[i-1]+T[1][j-wgt[i-1]],T[1][j]);
else
T[0][j]=T[1][j];
}
}
else
{
for(j=0;j<W+1;j++)
{
if(i==0 || j==0)
T[1][j]=0;
else if(wgt[i-1]<=j)
T[1][j]=max(val[i-1]+T[0][j-wgt[i-1]],T[0][j]);
else
T[1][j]=T[0][j];
}
}
}
if(n%2!=0)
return T[1][W];
else
return T[0][W];
}
int main()
{
int n,i,j,index,t,mintime,maxval;
float maxr;
cin>>n;
cin>>t;
for(i=0;i<n;i++)
cin>>a[i];
for(i=0;i<n;i++)
cin>>b[i];
maxr=0;
index=0;
mintime=b[0];
maxval=a[0];
for(i=0;i<n;i++)
{
c[i]=(float)a[i]/b[i];
if(c[i]==maxr && b[i]<=t)
{
if(a[i]>=maxval)
{
maxval=a[i];
mintime=b[i];
index=i;
}
}
else if(c[i]>maxr && b[i]<=t)
{
maxr=c[i];
maxval=a[i];
mintime=b[i];
index=i;
}
}
a[index]=a[index]*2;
int xx=knapSack(t,a,b,n);
printf("%d\n",xx);
}
【问题讨论】:
-
当问题需要准确答案时,为什么要使用贪心近似?
-
@user2357112:因为我想不出更好的方法
-
蛮力法是解N个背包(在每个背包中选择另一个问题进行加倍)并采取整体最佳解决方案。
-
@Henry:感谢您提出蛮力方法,但这肯定会超出时间限制
-
@user2357112:我已经知道暴力破解了。还有比这更好的吗?
标签: arrays algorithm knapsack-problem