问题:
考试由N个问题组成。 N个问题的标记分别为m1,m2,m3,... mN。 Jam正在参加考试,他希望最大化他的分数。 但是他需要一些时间来解决每个问题。他解决问题所花费的时间分别为t1,t2,t3,... tN。 考试总共持续时间T. 但Jam的老师很聪明,她知道Jam会找到一种获得最大分数的方法。所以,为了混淆Jam,她还为他提出了奖金 - 该提议是Jam可以选择一个问题,他可以将该问题的分数加倍。 现在,Jam确实很困惑。帮助他找出他可以获得的最大分数。
约束
1·; = N< = 1000
1·; = T< = 10000
1·= MI< = 100000
1·= TI< = 10000
我尝试了这个问题here并提出了以下算法:
由于问题所在,我们可以选择一个问题,他可以将该问题的分数加倍。
因此,为了选择那个问题,我应用了贪婪方法,即
如果该比率也相同,则应选择具有较大标记的问题。
就我所理解的问题而言,其余的都是简单的背包。 我尝试了以下实现,但得到了错误的答案。 对于给定的测试用例,我的代码提供了正确的输出
3 10 1 2 3 4 3 4
我已经尝试了在评论部分给出的这个测试用例,我的代码给出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);
}
答案 0 :(得分:4)
要解决这个问题,我们先来看the wikipedia article on the Knapsack problem,为常规问题提供动态编程解决方案:
// Input:
// Values (stored in array v)
// Weights (stored in array w)
// Number of distinct items (n)
// Knapsack capacity (W)
for j from 0 to W do
m[0, j] := 0
end for
for i from 1 to n do
for j from 0 to W do
if w[i] <= j then
m[i, j] := max(m[i-1, j], m[i-1, j-w[i]] + v[i])
else
m[i, j] := m[i-1, j]
end if
end for
end for
(正如文章所说,你可以通过使用1-d数组m而不是2-d数组来减少内存使用量。)
现在我们可以用这个想法来解决扩展问题。您可以计算两个表:而不是m,您可以计算m0和m1。 m0 [i,w]存储使用带有权重(在您的情况下是时间)最多w,的第i个项目获得的最大值,而不使用双重评分问题。类似地,m1存储使用第一个i项目获得的最大值,其中权重(在您的情况下为时间)最多为w,使用双重评分问题。
更新规则更改为:
if w[i] <= j then
m0[i, j] := max(m0[i-1, j], m0[i-1, j-w[i]] + v[i])
m1[i, j] := max(m1[i-1, j], m1[i-1, j-w[i]] + v[i], m0[i-1, j-w[i]] + 2 * v[i])
else
m0[i, j] = m0[i-1, j]
m1[i, j] = m1[i-1, j]
end if
与常规问题一样,您可以使用两个1-d数组而不是两个2-d数组来减少内存使用量。
答案 1 :(得分:-1)