关闭

UVa 10280 Old Wine Into New Bottles / 完全背包

682人阅读 评论(0) 收藏 举报
分类:

转自http://blog.csdn.net/yan_____/article/details/8671147

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;

}


 

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:653456次
    • 积分:14406
    • 等级:
    • 排名:第864名
    • 原创:763篇
    • 转载:192篇
    • 译文:0篇
    • 评论:58条
    博客专栏
    文章分类
    最新评论