您的位置:首页 > 其它

uva 10280 Old Wine Into New Bottles 有剪枝的完全背包

2013-03-14 01:47 375 查看
uva 10280

1、这道题如果直接把每个酒瓶的可用容量来做完全背包的话会超时,但是由最低的容量不低于95%,最高的容量不超过99%,由于容量的连续性有一些规律可循,可藉此优化:

考虑任意一种瓶子能够将酒全装满的情况,最小容量min,最大容量max,只要酒的体积x在[min,max]|[2*min,2*max]|……[k*min,k*max]的范围内就能完全装满,而max比min大,倍乘后单个区间长度会越来越长,而区间左端保持等距,右端距离越来越远,每当增加一个k,上一区间的右端点与当前区间的左端点距离就会减小(max-min),所以当(k+1)增加到(min*2-max)/(max-min)时各个区间就会相连,即min*(k+1)>max*k,得到k<min/(max-min),我们要求的边界就是k*min<min*min/(max-min),在这之后x都能装满

举个例子min=95,max=99

95 99

190 198

285 297

380 396

475 495

570 594

665 693

760 792

855 891

950 990

1045 1089

1140 1188

1235 1287

1330 1386

1425 1485

1520 1584

1615 1683

1710 1782

1805 1881

1900 1980

1995 2079

2090 2178

2185 2277

2280 2376//这里开始相连,2280是边界

2375 2475

2470 2574

2565 2673

2660 2772

2755 2871

2850 2970

2945 3069

3040 3168

3135 3267

3230 3366

3325 3465

3420 3564





2、瓶子最多有100个,全部满足的容量可能会有重叠,如果忽视重复容量会超时

#include<stdio.h>
#include<string.h>
#define s 2500
#define maxn 450000
int v;
int dp[maxn],vis[4600],c[4600];
int a[110],b[110];
int main()
{
int i,j,k,l,n,m;
int t;
scanf("%d",&t);
while(t--)
{
k=1<<30;
scanf("%d %d",&v,&n);
v=v*1000;
dp[0]=1;
for(i=0;i<n;i++)
{
scanf("%d %d",&a[i],&b[i]);
if(k>a[i]*a[i]/(b[i]-a[i]))
k=a[i]*a[i]/(b[i]-a[i]);
}
if(v>=k)
{
printf("0\n");
if(t)
printf("\n");
}
else
{
m=0;
memset(vis,0,sizeof(vis));
memset(dp,0,sizeof(dp));
for(i=0;i<n;i++)
{
for(j=a[i];j<=b[i];j++)
{
if(!vis[j])
{
c[m++]=j;
vis[j]=1;
}
}
}
dp[0]=1;
for(i=0;i<m;i++)
{
for(j=c[i];j<=v;j++)
if(dp[j-c[i]]==1)
dp[j]=1;
}
for(i=v;i>=0;i--)
{
if(dp[i])
break;
}
printf("%d\n",v-i);
if(t)
printf("\n");
}
}
return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: