SDUT_背包。

1001 http://acm.hdu.edu.cn/diy/contest_showproblem.php?pid=1001&cid=13996

原来做过的一道题目,我用的贪心,按比重从大到小排序,然后依次选直到不能再放进来为止。

注意两点:1:F[j]可能为0因为题目中说的非负数。记得第一次做的时候wa无数次。。

2:选完的时候有2种可能:1:n恰好用完,最后不能再选;2:n有剩余,可能n比较大把所有的都选了还有剩余,可能中间出现不能全部将这间屋子里的换完只能换部分。

View Code
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int max_s = 1007;
struct node
{
int a,b;
double rate;
}p[max_s];
int cmp(node x,node y)
{
return x.rate>y.rate;
}
int main()
{
//freopen("d.txt","r",stdin);
int n,m,i;
while(scanf("%d%d",&n,&m))
{
if(n==-1&&m==-1) break;
int k=0;
double sum=0;
int x,y;
for(i=0;i<m;i++)
{
scanf("%d%d",&x,&y);
if(y==0)
{
sum+=x;
continue;
}
p[k].a=x;
p[k].b=y;
p[k].rate=(1.0*x)/(1.0*y);
k++;
}
sort(p,p+k,cmp);
/*for(i=0;i<k;i++)
printf("%d %d %.2lf\n",p[i].a,p[i].b,p[i].rate);
*/
i=0;
while(n>=p[i].b&&i<k)
{
sum+=p[i].a;
n-=p[i].b;
i++;
}
if(i<k) sum+=(p[i].rate)*(n);
printf("%.3lf\n",sum);
}
return 0;
}

1002 http://acm.hdu.edu.cn/diy/contest_showproblem.php?pid=1002&cid=13996&hide=0

直接0-1背包的模板题。。

1003 http://acm.hdu.edu.cn/diy/contest_showproblem.php?pid=1003&cid=13996&hide=0

第一次接触二维背包的题目。以前看的时候只是看了0-1,完全以及多重背包。后边的都没看,看来要加把劲了。。

直接调用背包就讲里的模板,但是处理的时候注意0—1背包讲解时的预处理。对于m必须恰要选择m个,初始化为-1;

View Code
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int max_s = 1007;
int tc[max_s],w[max_s],f[max_s][max_s];
int main()
{
//freopen("d.txt","r",stdin);
int t,n,m,L,i,j,k;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&L);
int num=0,x,y;
for(i=0;i<n;i++)
{
scanf("%d%d",&x,&y);
if(x>L) continue;
tc[num]=x;
w[num]=y;
num++;
}
for(i=0;i<=m;i++)
{
for(j=0;j<=L;j++)
{
if(i==0)
f[i][j]=0;
else
f[i][j]=-1;
}
}
for(i=0;i<num;i++)
{
for(j=m;j>=1;j--)
{
for(k=L;k>=tc[i];k--)
{
if(f[j-1][k-tc[i]]!=-1)
f[j][k]=max(f[j][k],f[j-1][k-tc[i]]+w[i]);
}
}
}
if(f[m][L]<0)
puts("0");
else
cout<<f[m][L]<<endl;
}
return 0;
}

1004 http://acm.hdu.edu.cn/diy/contest_showproblem.php?pid=1004&cid=13996&hide=0

多重背包问题用的背包九讲里面转换成0-1背包的三重循环解得。最后自己又敲了一遍利用二进制思想的代码。这个不到理解。只是记住了模板。。

View Code
三重循环的代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int max_s = 107;
int v[max_s],w[max_s],b[max_s],f[max_s];
int main()
{
int t,i,j,k,n,m;
scanf("%d",&t);
while(t--)
{
memset(f,0,sizeof(f));
scanf("%d%d",&n,&m);
for(i=0;i<m;i++)
scanf("%d%d%d",&v[i],&w[i],&b[i]);
for(i=0;i<n;i++)
{
for(k=1;k<=b[i];k++)
{
for(j=n;j>=v[i];j--)
{
f[j]=max(f[j],f[j-v[i]]+w[i]);
}
}
}
printf("%d\n",f[n]);
}

return 0;
}
View Code
二进制思想的代码:

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int max_s = 1007;
int c[max_s],w[max_s],b[max_s],f[max_s];
void zb(int c,int w,int n)
{
for(int i=n;i>=c;i--)
f[i]=max(f[i],f[i-c]+w);
}
void cb(int c,int w,int n)
{
for(int i=c;i<=n;i++)
{
f[i]=max(f[i],f[i-c]+w);
}
}
int main()
{
int t,i,n,m;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(i=0;i<m;i++)
scanf("%d%d%d",&c[i],&w[i],&b[i]);
memset(f,0,sizeof(f));
for(i=0;i<m;i++)
{
if(c[i]*b[i]>n)//多余最大值转化成完全背包解
cb(c[i],w[i],n);
else//否则调用二进制思想
{
int k=1;
while(k<b[i])
{
zb(k*c[i],k*w[i],n);
b[i]-=k;
k*=2;
}
zb(b[i]*c[i],b[i]*w[i],n);
}
}
printf("%d\n",f[n]);
}
return 0;
}






posted @ 2011-12-06 16:46  E_star  阅读(225)  评论(0编辑  收藏  举报