• 2017-7-17/18 背包dp cf round 417 div2


      poj3624

     0-1背包 裸 

     1 #include<iostream>
     2 #include<cstdio>
     3 
     4 using namespace std;
     5 const int maxn=15000;
     6 int w[maxn];
     7 int v[maxn];
     8 int cost;
     9 int main()
    10 {
    11     int n,m;
    12     scanf("%d%d",&n,&cost);
    13     for(int i=0;i<n;i++)
    14     {
    15         scanf("%d%d",&w[i],&v[i]);
    16     }
    17     int dp[maxn];
    18     memset(dp,0,sizeof(dp));
    19     for(int i=0;i<n;i++)
    20     {
    21         for(int j=cost;j>=w[i];j--)
    22         {
    23             dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
    24         }
    25     }
    26     cout<<dp[cost]<<endl;
    27 }

       poj3628

    2^20 枚举即可

     1 #include<iostream>
     2 #include<stdio.h>
     3 #include<cstring>
     4 #include<vector>
     5 
     6 using namespace std;
     7 
     8 int a[22];
     9 int n,m;
    10 
    11 
    12 int cal(int x)
    13 {
    14     int i=0;
    15     int sum=0;
    16     while(x)
    17     {
    18         if(x&1) sum+=a[i];
    19         x>>=1;
    20         i++;
    21     }
    22     return sum;
    23 }
    24 
    25 
    26 int main()
    27 {
    28     scanf("%d%d",&n,&m);
    29     for(int i=0;i<n;i++)
    30         scanf("%d",&a[i]);
    31 
    32     int num=2e9;
    33 
    34     for(int i=0;i<=(1<<n)-1;i++)
    35     {
    36         int d=cal(i);
    37         if(d<num&&d>=m) num=d;
    38     }
    39     printf("%d
    ",num-m);
    40 }

    方法2:  0-1背包 用所有cow的高度和作为背包体积V,最后找到最小的但是大于m的即可,背包体积从小到大枚举找到ans

    #include<iostream>
    #include<stdio.h>
    #include<cstring>
    #include<vector>
    
    using namespace std;
    
    int dp[20000005];
    int a[22];
    
    int main()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        int sum=0;
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]),sum+=a[i];
        dp[0]=0;
        for(int i=0;i<n;i++)
        {
            for(int j=sum;j>=a[i];j--)
                dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
        }
        for(int i=0;i<=sum;i++)
        {
            if(dp[i]>=m) {printf("%d
    ",dp[i]-m);break;}
        }
        
    }

     poj 1837 

    题意:背包变形,在一个天平上有一些挂钩 一些砝码,将所有砝码挂上去,问使得天平平衡的方案数是多少?

    思路:类似背包 这里使用7500作平衡点,另外dp[i][j]表示前i个砝码都放上去,平衡度为j时的方案数目,引入平衡度的概念。那么dp[i][j]=sigma(dp[i-1][j-c[k]*w[i]]),0<=k<n, ans=dp[m][7500];

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    
    using namespace std;
    
    int n,m;
    
    int w[50];
    int c[50];
    int dp[22][15010];
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d",&c[i]);
        for(int i=1;i<=m;i++) scanf("%d",&w[i]);
        memset(dp,0,sizeof(dp));
        dp[0][7500]=1;
    
        for(int i=1;i<=m;i++)
        {
            for(int j=0;j<=15000;j++)
            {
                for(int k=1;k<=n;k++)
                {
                    dp[i][j]+=dp[i-1][j-c[k]*w[i]];
                    //dp[i][j+c[k]*w[i]]+=dp[i-1][j];
                }
            }
        }
    
    
        printf("%d
    ",dp[m][7500]);
    }

     hdu 2548 饭卡

    思路:如果余额小于5元,就直接输出余额,如果余额大于五元就直接留出来买最贵的那个,然后去掉五元之外的钱,用来做0-1背包,买其他的物品

    #include<bits/stdc++.h>
    
    using namespace std;
    
    int w[1010];
    int dp[50000+100];
    int t;
    int cost;
    int n;
    
    int main()
    {
        while(~scanf("%d",&n)&&n)
        {
            for(int i=0;i<n;i++) scanf("%d",&w[i]);
            scanf("%d",&cost);
            if(cost<5) {printf("%d
    ",cost);continue;}
            sort(w,w+n);
            cost-=5;
            memset(dp,0,sizeof(dp));
            for(int i=0;i<n-1;i++)
            {
                for(int j=cost;j>=w[i];j--)
                    dp[j]=max(dp[j],dp[j-w[i]]+w[i]);
            }
            printf("%d
    ",cost-dp[cost]+5-w[n-1]);
        }
        return 0;
    }

      poj 3903  nlog(n)求最长递增子序列LIS

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 
     6 using namespace std;
     7 
     8 int n;
     9 const int maxn=100010;
    10 const int inf=0x7fffffff;
    11 int dp[maxn];
    12 int a[maxn];
    13 
    14 int main()
    15 {
    16     while(~scanf("%d",&n))
    17     {
    18         for(int i=0;i<n;i++) scanf("%d",&a[i]);
    19 
    20         fill(dp,dp+n,inf);
    21 
    22         for(int i=0;i<n;i++)
    23             *lower_bound(dp,dp+n,a[i])=a[i];
    24         int ans=lower_bound(dp,dp+n,inf)-dp;
    25         printf("%d
    ",ans);
    26     }
    27 }

     hdu 1203 0-1背包变形

    题意:qn要去申请n所学校,但是只有cost前,每所学校都有申请费用以及录取概率,求qn有学上的最大概率

     1 #include<bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 double dp[10010];
     6 int w[10010];
     7 double p[10010];
     8 int n,cost;
     9 
    10 double cal(double x,double y)
    11 {
    12     double c=1.0-(1-x)*(1-y);
    13     return c;
    14 }
    15 
    16 int main()
    17 {
    18     while(~scanf("%d%d",&cost,&n)&&(cost||n))
    19     {
    20         for(int i=0;i<n;i++)
    21             scanf("%d%lf",&w[i],&p[i]);
    22         memset(dp,0,sizeof(dp));
    23         for(int i=0;i<n;i++)
    24         {
    25             for(int j=cost;j>=w[i];j--)
    26                 dp[j]=max(dp[j],cal(dp[j-w[i]],p[i]));
    27         }
    28         printf("%.1f%%
    ",dp[cost]*100);
    29     }
    30 }

     hdu 2955 

    题目大意:rob计划要抢银行,一共有n个银行,给定逃跑概率上限值lim(安全概率),对每个银行都有一个可以抢的钱数以及被抓的概率,问你在保证安全情况下,最多抢到多少钱?

    思路:这题从被抓概率考虑,我们肯定要求最小的,这样就违背了背包的原理,我们反过来,从逃跑概率出发,也就是说求逃跑概率最大值满足条件,我们把抢到的钱看做体积,逃跑概率看做价值,这样背包之后,再从末尾往前查满足条件的即可,需要注意的是边界要进行初始化,0的时候 就是不抢 概率为1 ,同时还要注意一定要恰好装满背包 需要重复查一次

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 
     4 int t;
     5 int n;
     6 int cost;
     7 double lim;
     8 int w[110];
     9 double p[110];
    10 
    11 double dp[10010];
    12 
    13 double cal(double x,double y)
    14 {
    15     return x*y;
    16 }
    17 int main()
    18 {
    19     scanf("%d",&t);
    20     while(t--)
    21     {
    22         cost=0;
    23         scanf("%lf%d",&lim,&n);
    24         lim=1-lim;
    25         for(int i=0;i<n;i++)
    26             scanf("%d%lf",&w[i],&p[i]),cost+=w[i],p[i]=1-p[i];
    27         memset(dp,0,sizeof(dp));
    28         dp[0]=1;
    29 
    30         for(int i=0;i<n;i++)
    31         {
    32             for(int j=cost;j>=w[i];j--)
    33             {
    34                 dp[j]=max(dp[j],cal(dp[j-w[i]],p[i]));
    35             }
    36         }
    37 
    38         int ans;
    39         for(int i=cost;i>=0;i--)
    40         {
    41             if(dp[i]>=lim) {
    42                 ans=i;
    43                 break;
    44             }
    45         }
    46         int pos=0;
    47         for(int i=ans;i>=1;i--)
    48         {
    49             if(dp[i]!=dp[i-1]){
    50                 pos=i;
    51                 break;
    52             }
    53         }
    54 
    55         printf("%d
    ",pos);
    56     }
    57 }

    poj  1948   Triangular Pastures 子集和问题

    题目大意:有n个木棒,给出每个木棒的长度,将所有三角形都用上,求所能构成的三角形的最大面积,最后结果乘以100   向下取整,若不能构成三角形 输出-1;

    题目思路,dp[i][j][k]表示前i个木棒能不能拼成两条边的长度分别为j和k,那么第三条边就可以减法求出来

      dp[i][j][k]=(dp[i-1][j][k]|dp[i-1][j-w[i]][k]|dp[i-1][j][k-w[i]]); 由于内存限制,优化掉第一层,滚动数组

     1 #include<iostream>
     2 #include<stdio.h>
     3 #include<cstring>
     4 #include<cmath>
     5 
     6 using namespace std;
     7 
     8 int n;
     9 int w[50];
    10 bool dp[1610][1610];
    11 
    12 double cal(double p,int a,int b,int c)
    13 {
    14     return sqrt(double(p*1.0*(p-a)*(p-b)*(p-c)));
    15 }
    16 
    17 
    18 
    19 int main()
    20 {
    21     scanf("%d",&n);
    22     int sum=0;
    23     for(int i=0;i<n;i++)
    24         scanf("%d",&w[i]),sum+=w[i];
    25     memset(dp,0,sizeof(dp));
    26     dp[w[0]][0]=dp[0][w[0]]=1;
    27 
    28     double ans=0;
    29 
    30     int flag=0;
    31 
    32     for(int i=1;i<n;i++)
    33     {
    34         for(int j=sum;j>=0;j--)
    35         {
    36             for(int k=sum;k>=0;k--)
    37             {
    38                 if(j-w[i]>=0) dp[j][k]|=dp[j-w[i]][k];
    39                 if(k-w[i]>=0) dp[j][k]|=dp[j][k-w[i]];
    40                 int c=sum-j-k;
    41                 if(dp[j][k]&&j+k>c&&j+c>k&&k+c>j){
    42                     ans=max(ans,cal(sum/2.0,j,k,c));
    43                     flag=1;
    44                 }
    45             }
    46         }
    47     }
    48     if(flag)
    49         printf("%d
    ",int(ans*100));
    50     else puts("-1");
    51 
    52 }

    题目大意:有一个十字路口的交通灯,给出各种左转,右转,直行,人行横道,判断是否会撞到人行横道

    思路:分别对直行、左转、右转进行判断即可

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 
     4 int l[4];
     5 int s[4];
     6 int r[4];
     7 int p[4];
     8 
     9 int main()
    10 {
    11     for(int i=0;i<4;i++)
    12         cin>>l[i]>>s[i]>>r[i]>>p[i];
    13     for(int i=0;i<4;i++)
    14     {
    15         if((l[i]||r[i]||s[i])&&p[i]){
    16             cout<<"YES";return 0;
    17         }
    18     }
    19     for(int i=0;i<4;i++)
    20     {
    21         if(r[i]&&p[(i+1)%4]){
    22             cout<<"YES";return 0;
    23         }
    24     }
    25     for(int i=0;i<4;i++)
    26     {
    27         if(l[i]&&p[(i+4-1)%4]){
    28             cout<<"YES";return 0;
    29         }
    30     }
    31     for(int i=0;i<4;i++)
    32     {
    33         if(s[i]&&p[(i+2)%4])
    34         {
    35             cout<<"YES";return 0;
    36         }
    37     }
    38     cout<<"NO";
    39     return 0;
    40 }

    B

    题目大意:一个矩阵,最左右两列表示楼梯,中间的m列表示灯,走一步需要1min,每次关完本层的灯,再去关上层的灯,从左下角出发,求关完所有的灯需要的时间

    思路:

    预处理一下,对每一层从左边或者右边出发 需要花费多少时间,进行二进制枚举每一层从左边走还是右边走,用pre保存下一层从左边走的还是从右边走的,然后进行枚举求最小值,

    注意两个地方:

    一是注意预处理一下需要走上第几层,二是不需要向上走时,就不用再动了,二进制枚举右移次数有限制

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 
     4 int n,m;
     5 int ma[20][110];
     6 int l[20];
     7 int r[20];
     8 const int inf=0x7fffffff;
     9 
    10 
    11 int main()
    12 {
    13     memset(l,0,sizeof(l));
    14     memset(r,0,sizeof(r));
    15     char c;
    16     cin>>n>>m;
    17     for(int i=0;i<n;i++)
    18     {
    19         for(int j=0;j<m+2;j++)
    20         {
    21             cin>>c;
    22             ma[i][j]=c-'0';
    23         }
    24     }
    25     for(int i=n-1;i>=0;i--)
    26     {
    27         for(int j=0;j<m+2;j++)
    28         {
    29             if(ma[i][j]==1){
    30                 l[i]=max(l[i],j);
    31                 r[i]=max(r[i],m+1-j);
    32             }
    33         }
    34     }
    35 
    36     int flag=n-1;
    37     for(int i=0;i<n;i++)
    38     {
    39         if(l[i]) {flag=i;break;}
    40     }
    41 
    42     int ans=inf;
    43     for(int i=0;i<=(1<<(n-1))-1;i++)
    44     {
    45         int p=i;
    46         int sum=0;
    47         int pre=0;
    48         for(int j=n-2,k=0;j>=0&&k<n-1-flag;j--,k++)
    49         {
    50             if(p&1){
    51                 if(pre){
    52                     sum+=r[j+1]+r[j];
    53                     pre=1;
    54                 }
    55                 else {
    56                     sum+=(m+1-l[j+1])+r[j];
    57                     pre=1;
    58                 }
    59             }
    60             else{
    61                 if(pre){
    62                     sum+=(m+1-r[j+1])+l[j];
    63                     pre=0;
    64                 }
    65                 else {
    66                     sum+=l[j+1]+l[j];
    67                     pre=0;
    68                 }
    69             }
    70             p>>=1;
    71         }
    72         sum+=l[n-1];
    73         sum+=n-1-flag;
    74 
    75         ans=min(ans,sum);
    76     }
    77     cout<<ans;
    78 }

      C 

    简单二分,

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 
     4 typedef long long LL;
     5 
     6 int n,cost;
     7 struct node
     8 {
     9     int v;
    10     int ord;
    11     LL cal;
    12 }a[100000+100];
    13 const int inf=0x7fffffff;
    14 LL num=inf;
    15 
    16 int cmp(node u,node v)
    17 {
    18     if(u.cal<v.cal) return 1;
    19     else return 0;
    20 }
    21 
    22 int check(int x)
    23 {
    24     LL sum=0;
    25     for(int i=1;i<=n;i++)
    26     {
    27         a[i].cal=a[i].ord*1LL*x+a[i].v;
    28     }
    29     sort(a+1,a+n+1,cmp);
    30     for(int i=1;i<=x;i++)
    31     {
    32         sum+=a[i].cal;
    33         if(sum>cost*1LL) return 0;
    34     }
    35 
    36 
    37 
    38     num=sum;
    39 
    40     return 1;
    41 }
    42 
    43 
    44 int main()
    45 {
    46     scanf("%d%d",&n,&cost);
    47     for(int i=1;i<=n;i++)
    48     {
    49         scanf("%d",&a[i].v);
    50         a[i].ord=i;
    51     }
    52     int l=0,r=n;
    53     int ans=0;
    54     while(l<=r)
    55     {
    56 
    57         int mid=(l+r)/2;
    58         if(check(mid)) {
    59             ans=mid;
    60             l=mid+1;
    61         }
    62         else {
    63             r=mid-1;
    64         }
    65     }
    66     printf("%d %I64d
    ",ans,num);
    67 }
  • 相关阅读:
    JavaScript打造很酷的图片放大效果实例代码
    【荐】CSS实现的鼠标点击小图无刷新放大图片代码
    JavaScript+CSS实现的文字幻灯切换代码
    【荐】很棒的图片友情链接带控制按钮的横向滚动代码
    jquery制作一个漂亮带渐隐效果的跑动区域
    JS打造的一款响应鼠标变化很炫的图片特效代码
    JS+CSS控制鼠标移上图片滑出文字提示代码
    Jquery+CSS实现的大气漂亮图片切换效果代码
    【荐】JS+CSS防FLASH效果带倒影的图片切换效果代码
    JavaScript限制对图片右键代码
  • 原文地址:https://www.cnblogs.com/hellohacker/p/7196177.html
Copyright © 2020-2023  润新知