一个劫匪带着一个可装m重量的超大背包去抢银行,银行有n个大箱子,第i个箱子里有i个重量为wi,价值为ci的大钻石,问该劫匪抢走钻石的最大价值
Input
第一行为一整数T表示用例组数,每组用例第一行为两个整数n和m分别表示钻石个数和背包可装钻石重量上限,第二行为n个整数wi表示第i箱子中每颗钻石的重量,第三行为n个整数ci表示第i箱子中每颗钻石的价值。
数据范围:(1<=T<=74,1<=n<=15,1<=wi,ci,m<=1e9)
Output
对于每组用例,输出该劫匪带走钻石的最大价值
Sample Input
2
2 4
3 2
5 3
3 100
4 7 1
5 9 2
Sample Output
6
29
思路:完全背包问题,可用DFS大法解,用weight表示当前重量,用ans表示劫匪能偷走最大价值,再递归调用求解,每次动态求出当前(局部)可偷出的最大价值,再算出整体的最大价值,但WA了,一分没得
参考代码(WA)
#include <iostream>
using namespace std;
int w[16],v[16],k[16];
int n,m,time;
int ans,sum[16];
void turn(int &x,int &y)
{
int temp;
temp=x;
x=y;
y=temp;
}
void sort()
{
int i,j,temp;
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
if(v[i]*w[j]<v[j]*w[i])
{
turn(w[i],w[j]);
turn(v[i],v[j]);
turn(k[i],k[j]);
}
}
void put(int x)
{
if (ans<x) ans=x;
}
void dfs(int left,int x,int value)
{
int i;
if (x>n)
{
put(value);
return;
}
if(time==2147483647)
return;
double cost;
cost=value+((double)left)/w[x]*v[x];
if(cost<ans)
return;
cost=value+sum[n]-sum[x-1];
if(cost<ans)
return;
for(int i=k[x];i>=0;i--)
if(left>=i*w[x])
{
time++;
dfs(left-i*w[x],x+1,value+i*v[x]);
}
}
int main()
{
freopen("robbery.in","r",stdin);
freopen("robbery.out","w",stdout);
int i,t;
int weight;
cin>>t;
for(int i=1;i<=t;i++)
{
cin>>n>>m;
weight=0;
for(int j=1;j<=n;j++)
{
cin>>w[j];
weight+=w[j]*i;
}
for(int j=1;j<=n;j++)
{
cin>>v[j];
k[j]=j;
}
sort();
sum[0]=0;
for(int j=1;j<=n;j++)
sum[j]=sum[j-1]+v[j]*k[j];
ans=0;
int mm=m;
for(int i=1;i<=n;i++)
if(mm>=w[i])
if(mm>=w[i]*k[i])
{
ans+=v[i]*k[i];
mm-=w[i]*k[i];
}
else
{
ans+=(mm/w[i])*v[i];
mm=mm-w[i]*(mm/w[i]);
}
time=0;
if(weight>m)
dfs(m,1,0);
else
ans=sum[n];
cout<<ans;
}
return 0;
}
2、egypt
Description
在古埃及,人们使用单位分数的和(形如1/a的, a是自然数)表示一切有理数。 如:2/3=1/2+1/6,但不允许2/3=1/3+1/3,因为加数中有相同的。 对于一个分数a/b,表示方法有很多种,但是哪种最好呢?
首先,加数少的比加数多的好,其次,加数个数相同的,最小的分数越大越 好。 如:
19/45=1/3 + 1/12 + 1/180
19/45=1/3 + 1/15 + 1/45
19/45=1/3 + 1/18 + 1/30
19/45=1/4 + 1/6 + 1/180
19/45=1/5 + 1/6 + 1/18.
最好的是最后一种,因为1/18比1/180,1/45,1/30,1/180都大。
给出a,b(0 < a < b < 1000),编程计算最好的表达方式。
输入描述 Input Description
a b
输出描述 Output Description
若干个数,自小到大排列,依次是单位分数的分母。
样例输入 Sample Input
19 45
样例输出 Sample Output
5 6 18
思路:根据题目意思,将a/b分层,第一层1/10,第二层10-100-----再定义DFS函数求解,开始只得了70分,后来发现(0 < a < b < 1000)的条件后,发现调用函数时会超时,把int改为long long 即可AC
参考代码:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int depth=0,min1,aijifenshu1;
int ans[110],out[110];
void dfs(int a,int b,int x)
{
if(depth>=aijifenshu1||x>=min1)
return;
if(b%a==0)
{
b/=a;
if(b<x||b>=min1)
return;
ans[depth]=b;
min1=b;
memcpy(out,ans,(depth+1)*sizeof(int));
return;
}
else
{
if(depth>=aijifenshu1-1)
return ;
while(a*x<=b&&x<min1)
{
x++;
}
while(x<min1)
{
if(a*x>=b*(aijifenshu1-depth))
break;
ans[depth]=x;
depth++;
dfs(a*x-b,b*x,x+1);
depth--;
x++;
}
}
return ;
}
int main()
{
freopen("egypt.in","r",stdin);
freopen("egypt.out","w",stdout);
int a,b;
cin>>a>>b;
min1=2147483647;
for(aijifenshu1=1;aijifenshu1<=110;aijifenshu1++)
{
dfs(a,b,1);
if(min1<2147483647)
break;
}
for(int k=0;k<aijifenshu1-1;k++)
cout<<out[k]<<" ";
cout<<out[aijifenshu1-1];
return 0;
}