声明:这些题大多是板子题,HDU的多,新手题都是,题目就不贴了,直接点链接就行
题意:最裸的01背包,给你背包总量和物品数,以及物品的价值和体积,让你求背包装满后的最大价值
#include
using namespace std;
const int N = 1e3 + 10;
int w[N],v[N],dp[N];
int main(){
int T;cin>>T;
while(T--){
memset(dp,0,sizeof(dp));
int n,V;cin>>n>>V;
for(int i = 1;i <= n;i++)cin>>v[i];
for(int i = 1;i <= n;i++)cin>>w[i];
for(int i = 1;i <= n;i++){
for(int j = V;j >= w[i];j--){
dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
}
}
cout<return 0;
}
题意:给你n个菜的价格,没种菜只能买一次,再给你一个m,表示你卡上的余额,有个规定,就是可以用卡里最后的5元钱去购买所有菜里面最贵的一个菜,问你卡里面最少还剩多少钱
分析:首先贪心的先用5元钱,去买最贵的那一个菜,然后剩余的钱做一个01背包即可,哦对了,如果一开始的钱就小于5元的话就直接输出即可
#include
using namespace std;
const int N = 1e3 + 10;
int dp[N],a[N];
int main(){
ios_base::sync_with_stdio(0);
int n,V;
while(cin>>n&&n){
memset(dp,0,sizeof(dp));
for(int i = 1;i <= n;i++)cin>>a[i];
cin>>V;
if(V < 5)cout<else{
sort(a+1,a+n+1);//别忘记
for(int i = 1;i < n;i++){
for(int j = V - 5;j >= a[i];j--){
dp[j] = max(dp[j],dp[j-a[i]]+a[i]);
}
}
cout<5]-a[n]<return 0;
}
题意:首先看到浮点型的就得注意精度问题了,先给你两个数,一个是最大的“容错度”:P,就是如果这个人被警察抓住的概率大于这个值时就会被抓走,还有个时银行的数目,接下来输入的是每个银行的钱数和各自银行被抓到的概率
分析:因为这个浮点型的,不好直接求,也不能直接把那个所有的容错度都扩大一个倍数,这样理解是不对的,因为得考虑一个容斥,从正面分析有点复杂,不妨以反过来,以获得的钱为重量,以被抓的概率为价值,只要不被抓的概率小于等于(1-p)即可,这里面的概率运算可不是相加啦,而是相乘的,所以状态转移方程就是dp[j] = max{dp[j],dp[j-v[i]]*w[i]},最后从最大的开始枚举,只要大于等于(1-p)就输出即可
#include
using namespace std;
#define EPS 0.00000000001
struct node{
int v;double w;
}a[5007];
double dp[5007];
int main(){
ios_base::sync_with_stdio(false);
int T;cin>>T;
while(T--){
memset(dp,0,sizeof(dp));dp[0] = 1;
int n,sum_v = 0;double V;
cin>>V>>n;
V = 1 - V;
for(int i = 0;i < n;i++){
cin>>a[i].v>>a[i].w;
a[i].w = 1 - a[i].w;
sum_v += a[i].v;
}
for(int i = 0;i < n;i++){
for(int j = sum_v;j >= a[i].v;j--){
dp[j] = max(dp[j],dp[j-a[i].v]*a[i].w);
}
}
for(int i = sum_v;i >= 0;i--){
if(V - dp[i] < EPS){
cout<break;
}
}
}
return 0;
}
题意:与上一题类似,这次是求个最小值而已 max ->min,反过来求就行了,又是浮点数,而且最后那个’%’,我wa了三次,mdzz..
#include
using namespace std;
const int maxn = 10007;
int main(){
int v[maxn];
double dp[maxn],p[maxn];
int n,m;
while(cin>>n>>m && n+m){
for(int i = 0;i <= n;i++)dp[i] = 1.0;
for(int i = 0;i < m;i++){
cin>>v[i]>>p[i];
p[i] = 1 - p[i];
}
for(int i = 0;i < m;i++){
for(int j = n;j >= v[i];j--){
dp[j] = min(dp[j],dp[j-v[i]]*p[i]);
}
}
printf("%.1f%%\n",(1-dp[n])*100);
}
return 0;
}
题意:给你n组数据,包括两个值,一个设备的价值,和相应的数目,让你分成两份,尽可能的相等,最后输出两个数,保持前面那个数大于等于后面那个数
分析: 就是一个看似01背包的题,用另一个数组把所有值都包含,直接对sum/2 进行01背包即可
#include
using namespace std;
const int N = 1e5 + 10;
int dp[N];
vector<int> a;
int main(){
// ios_base::sync_with_stdio(0);
int n,t,x;
while(cin>>n && n > -1){
int sum = 0;
a.clear();
memset(dp,0,sizeof(dp));
for(int i = 0;i < n;i++){
cin>>x>>t;
sum += x*t;
while(t--) a.push_back(x);
}
int sum1 = sum/2;
for(int i = 0;i < a.size();i++){
for(int j = sum1;j >= a[i];j--){
dp[j] = max(dp[j],dp[j-a[i]]+a[i]);
}
}
printf("%d %d\n",max(dp[sum1],sum-dp[sum1]),min(dp[sum1],sum-dp[sum1]));
}
return 0;
}
待更新…………