原题链接
题目大意
有
n
n
n类题目,每一类题目有切掉他所需的时间和切掉他可以得到的分数,每一类题目都有无限多个,现在给你有限的时间,求出在有限的时间内你可以得到最多多少分。
S
a
m
p
l
e
\mathbf{Sample}
Sample
I
n
p
u
t
\mathbf{Input}
Input
1
\mathbf{1}
1
4 10800
18 3600 3 1800
22 4000 12 3000
28 6000 0 3000
32 8000 24 6000
S a m p l e \mathbf{Sample} Sample O u t p u t \mathbf{Output} Output 1 \mathbf{1} 1
50
S a m p l e \mathbf{Sample} Sample I n p u t \mathbf{Input} Input 2 \mathbf{2} 2
3 7200
50 5400 10 900
50 7200 10 900
50 5400 10 900
S a m p l e \mathbf{Sample} Sample O u t p u t \mathbf{Output} Output 2 \mathbf{2} 2
70
解题思路
本题有两种方法,第一种是
d
f
s
dfs
dfs,另一种是
d
p
dp
dp。
①
d
f
s
dfs
dfs
可以用
d
f
s
dfs
dfs裸搜,但是这样肯定是会
的,所以我们需要剪枝。
- 可行性剪枝
如果说不够时间,或者深度大过
n
n
n则退出。
这是最基本的剪枝,对于本题来说没什么大用,所以你会发现:后面的几个大数据点,
了,程序还需要进一步的优化。
- 最优性剪枝
对于每一道题,肯定都有他自己的效率,将效率求出来,即:
效
率
=
m
a
x
(
全
做
分
数
全
做
时
间
,
骗
分
分
数
骗
分
时
间
)
效率=max(\frac{\tiny{全做分数}}{\tiny{全做时间}},\frac{\tiny{骗分分数}}{\tiny{骗分时间}})
效率=max(全做时间全做分数,骗分时间骗分分数)
把题目按照效率从大到小排序,随后就出来了第二个剪枝:
如果说当前题目的效率
×
\times
×剩余时间
≤
\le
≤当前最多分数的话,那么因为后面的效率都
<
<
<当前效率,所以后面题目所得的分数肯定比现在要低,加上之后依然不能
>
>
>当前最多分数,所以直接退出。
上代码!
#include <stdio.h>
#include <algorithm>
using namespace std;
struct data
{
data(){}
data(int a,int b,int c,int d,double e)
{
v1=a,w1=b,v2=c,w2=d;
p=e;
}
int v1,w1,v2,w2;
double p;
};
data t[40];
int n,m,ans=0;
bool pd(data x,data y){return x.p>y.p;}
void dfs(int dep,int sum,int left)
{
if (left<0) return;
if (sum>ans) ans=sum;
if (dep>n) return;
if (sum+t[dep].p*left<ans) return;
dfs(dep+1,sum+t[dep].v1,left-t[dep].w1);
dfs(dep+1,sum+t[dep].v2,left-t[dep].w2);
dfs(dep+1,sum,left);
}
int main()
{
cin>>n>>m;
for (int i=1;i<=n;i++)
{
int v1,w1,v2,w2;
cin>>v1>>w1>>v2>>w2;
t[i]=data(v1,w1,v2,w2,max(v1/(w1*1.0),v2/(w2*1.0)));
}
sort(t+1,t+n+1,cmp);
dfs(1,0,m);
printf("%d\n",ans);
return 0;
}
②
d
p
dp
dp
用
d
p
dp
dp来做的话,这个其实就是一个改进版的
01
01
01背包,而每一题的两种做法,只需要取最大值就可以了,即:
设
d
p
j
dp_{j}
dpj为时间为
j
j
j是可以取得的最大分数,
w
1
i
w1_i
w1i,
w
2
i
w2_i
w2i为全做和骗分所需要的时间,
c
1
i
c1_i
c1i,
c
2
i
c2_i
c2i为全做和骗分可以拿到的分数。
d
p
j
=
max
(
d
p
j
,
[
j
≥
w
1
i
]
(
d
p
j
−
w
1
i
+
c
1
i
)
,
[
j
≥
w
2
i
]
(
d
p
j
−
w
2
i
+
c
2
i
)
)
dp_{j}=\max(dp_j,[j\geq w1_i](dp_{j-w1_i}+c1_i),[j\geq w2_i](dp_{j-w2_i}+c2_i))
dpj=max(dpj,[j≥w1i](dpj−w1i+c1i),[j≥w2i](dpj−w2i+c2i))
上代码
#include<iostream>
using namespace std;
int n,m;
int w1[40],c1[40],w2[40],c2[40];
int dp[1080010];
int main()
{
cin>>n>>m;
for(int i=1; i<=n; i++) cin>>c1[i]>>w1[i]>>c2[i]>>w2[i];
for(int i=1; i<=n; i++)
{
for(int j=m; j>=1; j--)
{
if(j>=w1[i]) dp[j]=std::max(dp[j],dp[j-w1[i]]+c1[i]);
if(j>=w2[i]) dp[j]=std::max(dp[j],dp[j-w2[i]]+c2[i]);
}
}
cout<<dp[m]<<endl;
return 0;
}
完美切题~