1. HDU 1203 I NEED A OFFER!
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1203
稍微转化下,dp[i]表示的是前i个学校不被接受的最小概率。
代码如下:
//include <bits/stdc++.h>
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <stack>
#include <time.h>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll MOD = 10007;
const int maxn = 1e4+5;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
template <class T>
inline bool scan_d(T &ret) {
char c; int sgn;
if (c = getchar(), c == EOF) return 0;
while (c != '-' && (c<'0' || c>'9')) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
int n,m;
double dp[maxn];
int v[maxn];
double g[maxn];
double ans=0;
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0) break;
for (int i=1;i<=m;i++)
{
scanf("%d%lf",&v[i],&g[i]);
}
dp[0]=1;
for (int i=0;i<=n;i++) dp[i]=1;
for (int i=1;i<=m;i++)
{
for (int j=n;j>=v[i];j--)
{
dp[j]=min(dp[j],dp[j-v[i]]*(1-g[i]));
}
}
double ans=0;
for (int i=0;i<=n;i++)
{
ans=max(ans,(1-dp[i])*100);
}
printf("%.1f%%\n",ans);
}
return 0;
}
2. HDU 2546 饭卡
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2546
先将m减去5,选物品中的最大值,然后dp
代码如下:
//include <bits/stdc++.h>
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <stack>
#include <time.h>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll MOD = 10007;
const int maxn = 1e3+5;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
template <class T>
inline bool scan_d(T &ret) {
char c; int sgn;
if (c = getchar(), c == EOF) return 0;
while (c != '-' && (c<'0' || c>'9')) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
int n,m;
int v[maxn];
int dp[maxn];
int main()
{
while(scanf("%d",&n)&&n)
{
int Max=-1,loc=0;
for (int i=1;i<=n;i++)
{
scanf("%d",&v[i]);
if(Max<v[i])
{
Max=v[i];
loc=i;
}
}
scanf("%d",&m);
m-=5;
memset (dp,0,sizeof(dp));
for (int i=1;i<=n;i++)
{
if(i==loc) continue;
for (int j=m;j>=v[i];j--)
{
dp[j]=max(dp[j],dp[j-v[i]]+v[i]);
}
}
int ans=0;
for (int i=0;i<=m;i++)
{
dp[i]+=Max;
ans=max(ans,dp[i]);
}
printf("%d\n",m+5-ans);
}
return 0;
}
3. HDU 2602 Bone Collector
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2602
裸的01背包。
代码如下:
//include <bits/stdc++.h>
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <stack>
#include <time.h>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll MOD = 10007;
const int maxn = 1e3+5;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
template <class T>
inline bool scan_d(T &ret) {
char c; int sgn;
if (c = getchar(), c == EOF) return 0;
while (c != '-' && (c<'0' || c>'9')) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
int t;
int n,v;
int a[maxn];
int b[maxn];
int dp[maxn];
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&v);
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for (int i=1;i<=n;i++)
{
scanf("%d",&b[i]);
}
memset (dp,0,sizeof(dp));
int ans=0;
for (int i=1;i<=n;i++)
{
for (int j=v;j>=b[i];j--)
{
dp[j]=max(dp[j],dp[j-b[i]]+a[i]);
ans=max(ans,dp[j]);
}
}
printf("%d\n",ans);
}
return 0;
}
4. HDU 1864 最大报销额
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1864
因为输入的金额有小数,所以需要进行扩大位数,将每个金额*100,变成整数的形式然后进行01背包dp。
注意此题如果出现别的类型的发票,按题目要求这种发票不进行处理,并且类型A,B,C中的每个金额总和大于600也是不行的,还有A+B+C的总额大于1000也是不符合要求的。
因为只有30个发票,而且每个发票的金额不超过1000,然后再进行转化为整数操作,所以需要开30*1000*100+50的dp数组。
还有dp的时候不能100,100的递减,需要处理到每一位小数,所以需要1,1的处理。
复杂度为9*1e7;
代码如下:
//include <bits/stdc++.h>
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <stack>
#include <time.h>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll MOD = 10007;
const int maxn = 3*1e6+50;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
template <class T>
inline bool scan_d(T &ret) {
char c; int sgn;
if (c = getchar(), c == EOF) return 0;
while (c != '-' && (c<'0' || c>'9')) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
double q;
int n,m;
int dp[maxn];
int a[35];
int main()
{
while(scanf("%lf%d",&q,&n)!=EOF)
{
if(n==0) break;
int qq=(int)(q*100);
for (int i=1;i<=n;i++)
{
scanf("%d",&m);
getchar();
int sum=0;
int ok=1;
int aa=0,bb=0,cc=0;
while(m--)
{
char c;
double x;
scanf("%c:%lf",&c,&x);
getchar();
int t=(int)(x*100);
if(c=='A')
{
aa+=t;
}
else if(c=='B')
{
bb+=t;
}
else if(c=='C')
{
cc+=t;
}
else
{
ok=0;
}
}
if(ok&&aa+bb+cc<=100000&&aa<=60000&&bb<=60000&&cc<=60000)
{
a[i]=aa+bb+cc;
}
else
{
a[i]=0;
}
}
memset (dp,0,sizeof(dp));
int ans=0;
for (int i=1;i<=n;i++)
{
for (int j=qq;j>=a[i];j--)
{
dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
ans=max(ans,dp[j]);
}
}
printf("%.2lf\n",ans/100.0);
}
return 0;
}
5. POJ 1293 Duty Free Shop
题目链接:
http://poj.org/problem?id=1293
利用01背包求出最大包装的巧克力数量,并记录下dp路径,然后判断剩下的巧克力数量是否小于另一种巧克力的数量。
代码如下:
//include <bits/stdc++.h>
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <stack>
#include <time.h>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll MOD = 10007;
const int maxn = 1e3+5;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
template <class T>
inline bool scan_d(T &ret) {
char c; int sgn;
if (c = getchar(), c == EOF) return 0;
while (c != '-' && (c<'0' || c>'9')) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
int dp[maxn];
int m,l;
int n;
int a[maxn];
int path[maxn];
int vis[maxn];
bool can ()
{
memset (dp,-1,sizeof(dp));
memset (path,-1,sizeof(path));
memset (vis,0,sizeof(vis));
dp[0]=0;
for (int i=1;i<=n;i++)
{
for (int j=m;j>=a[i];j--)
{
if(dp[j]<dp[j-a[i]]+a[i]&&dp[j-a[i]]!=-1)
{
dp[j]=dp[j-a[i]]+a[i];
path[j]=i;
}
}
}
vector<int>ans;
int q=m;
while(dp[q]==-1) q--;
while(q>0)
{
ans.push_back(path[q]);
vis[path[q]]=1;
q=dp[q]-a[path[q]];
}
int sum=0;
for (int i=1;i<=n;i++)
{
if(vis[i]==0) sum+=a[i];
}
if(sum>l) return false;
printf("%d ",ans.size());
sort(ans.begin(),ans.end());
for (int i=0;i<ans.size();i++)
{
printf("%d ",ans[i]);
}
printf("\n");
return true;
}
int main()
{
while(scanf("%d%d",&m,&l)!=EOF)
{
if(m==0&&l==0) break;
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
int ok;
ok=can();
if(ok) continue;
printf("Impossible to distribute\n");
}
return 0;
}
6. HDU 2955 Robberies
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2955
一开始看错题了,以为是概率相加,然后还将概率作为01背包的dp对象,然后概率*100,跑出的样例怎么也不对,发现会出现精度问题,看了disscuss发现可以把钱数看成dp对象,这个范围就是钱数总和,依然还是没有读对题。
之后看别人的题解,发现给出的是被抓的概率,所以求解不被抓的概率需要用1减去,而且概率之间是需要相乘,不能相加。
稍微改一下dp方程,然后dp完后倒着找第一个大于等于1减去p的。
代码如下:
//include <bits/stdc++.h>
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <stack>
#include <time.h>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll MOD = 10007;
const int maxn = 1e4+5;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
template <class T>
inline bool scan_d(T &ret) {
char c; int sgn;
if (c = getchar(), c == EOF) return 0;
while (c != '-' && (c<'0' || c>'9')) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
int t;
int n;
double v;
double dp[maxn];
int a[maxn];
double b[maxn];
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%lf%d",&v,&n);
memset (dp,0,sizeof(dp));
dp[0]=1;
int sum=0;
for (int i=1;i<=n;i++)
{
scanf("%d%lf",&a[i],&b[i]);
sum+=a[i];
}
for (int i=1;i<=n;i++)
{
for (int j=sum;j>=a[i];j--)
{
if(dp[j]<dp[j-a[i]]*(1-b[i]))
{
dp[j]=dp[j-a[i]]*(1-b[i]);
}
}
}
int ans=0;
double ansp=0;
for (int i=sum;i>=1;i--)
{
if(dp[i]>(1-v))
{
ans=i;
break;
}
}
printf("%d\n",ans);
}
return 0;
}
7. HDU 1114 Piggy-Bank
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1114
完全背包模板题。
代码如下:
//include <bits/stdc++.h>
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <stack>
#include <time.h>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll MOD = 10007;
const int maxn = 1e5+5;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
template <class T>
inline bool scan_d(T &ret) {
char c; int sgn;
if (c = getchar(), c == EOF) return 0;
while (c != '-' && (c<'0' || c>'9')) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
int t,n;
int dp[maxn];
int a[maxn];
int b[maxn];
int kong,man;
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&kong,&man);
int v=man-kong;
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d%d",&a[i],&b[i]);
}
for (int i=1;i<=v;i++)
{
dp[i]=INF;
}
dp[0]=0;
for (int i=1;i<=n;i++)
{
for (int j=0;j<=v;j++)
{
if(b[i]<=j)
{
dp[j]=min(dp[j],dp[j-b[i]]+a[i]);
// printf("dp[%d]=%d dp[%d]=%d\n",j,dp[j],j-b[i],dp[j-b[i]]);
}
}
}
if(dp[v]>=INF)
{
printf("This is impossible.\n");
}
else
{
printf("The minimum amount of money in the piggy-bank is %d.\n",dp[v]);
}
}
return 0;
}
8. POJ 1276 Cash Machine 多重背包模板
题目链接:
http://poj.org/problem?id=1276
代码如下:
//include <bits/stdc++.h>
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <stack>
#include <time.h>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll MOD = 10007;
const int maxn = 1e5+5;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
template <class T>
inline bool scan_d(T &ret) {
char c; int sgn;
if (c = getchar(), c == EOF) return 0;
while (c != '-' && (c<'0' || c>'9')) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
int dp[maxn];
int n;
int v;
int num[15];
int w[15];
void zero (int w)
{
for (int i=v;i>=w;i--)
dp[i]=max(dp[i],dp[i-w]+w);
}
void unlimit (int w)
{
for (int i=w;i<=v;i++)
dp[i]=max(dp[i],dp[i-w]+w);
}
void mul ()
{
for (int i=1;i<=n;i++)
{
if(num[i]*w[i]>v)
{
unlimit(w[i]);
}
else
{
int k=1;
while(num[i]>k)
{
zero (k*w[i]);
num[i]-=k;
k<<=1;
}
zero(num[i]*w[i]);
}
}
}
int main()
{
while(scanf("%d",&v)!=EOF)
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d%d",&num[i],&w[i]);
}
memset (dp,0,sizeof(dp));
mul();
int ans=0;
for (int i=1;i<=v;i++)
{
ans=max(ans,dp[i]);
}
printf("%d\n",ans);
}
return 0;
}