• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

plank george

人生豪迈,只不过是重头再来。
  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

Come to a spring outing BNU 29358

http://www.bnuoj.com/bnuoj/problem_show.php?pid=29358

这个题目的话,初看就想到要用背包,一个包一个包的装,装好两个包的话,就可以直接判断了。

当然中间还有剪枝的部分,代码中有很好的体现,这个怎么说呢,代码写了很多,但是是为了节省时间,比较划来的。

当然这个问题最重要的不是剪枝,而是背包算法的运用:如何标记第一个背包已经使用过的物品。

 

为了标记,我觉得使用二维dp数组比一维数组好,但是标记后的处理也十分重要,详见代码。

此处本人还耍了一点小聪明,标记的话,第二次读的时候n和整个数组都变了,突发奇想,把标记了的物品体积赋值为0.这样就不会影响其它的背包了。

代码如下:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 using namespace std;
  5 #define M 450
  6 #define mem0(f) memset(f,0,sizeof(f))
  7 int t;
  8 int n,c;
  9 int v[M];
 10 int dp[M][M];//二维背包数组
 11 int vis[M][M];//表示第i个物品在构成j时是否被选用
 12 int s;
 13 int ok;
 14 int biaoji[M];
 15 int main()
 16 {
 17     scanf("%d",&t);
 18     for(int tt=1;tt<=t;tt++)
 19     {
 20         ok=1;
 21         scanf("%d%d",&n,&c);
 22         s=0;
 23         mem0(v);
 24 
 25         for(int i=1;i<=n;i++)//用二维数组的话,一定要从1开始存入
 26         {
 27             scanf("%d",&v[i]);
 28             if(v[i]>c)
 29             {
 30                 ok=0;
 31             }
 32             s+=v[i];
 33         }
 34         if(s>3*c)ok=0;
 35         if(ok==0)
 36         {
 37             printf("Case %d: No\n",tt);
 38             continue;
 39         }
 40         int p=2;
 41        // mem0(dp);
 42        mem0(biaoji);
 43         while(p--)
 44         {
 45         mem0(vis);
 46         mem0(dp);
 47         for(int i=1;i<=n;i++)
 48         {
 49             //if(biaoji[i])continue;
 50             for(int k=c;k>=0;k--)
 51             {
 52                 //
 53                 if(k>=v[i])
 54                 {
 55                 if(dp[i-1][k]>dp[i-1][k-v[i]]+v[i])
 56                 {
 57                     dp[i][k]=dp[i-1][k];
 58                     vis[i][k]=0;
 59                 }
 60                 else
 61                 {
 62                     dp[i][k]=dp[i-1][k-v[i]]+v[i];
 63                     vis[i][k]=1;
 64                 }
 65                 }
 66                 else
 67                 {
 68                     dp[i][k]=dp[i-1][k];
 69                     vis[i][k]=0;
 70                 }
 71             }
 72         }
 73        // printf("tttttttttt%d\n",dp[n][c]);
 74         //第一个背包
 75 
 76         if(p==1&&dp[n][c]<(double)s/3)//剪枝
 77         {
 78             printf("Case %d: No\n",tt);
 79             break;
 80         }
 81         s-=dp[n][c];
 82         if(p==0&&dp[n][c]<(double)s/2)//剪枝
 83         {
 84             printf("Case %d: No\n",tt);
 85             break;
 86         }
 87 
 88         if(p==0)
 89         {
 90             s<=c;
 91             printf("Case %d: Yes\n",tt);
 92             break;
 93         }
 94         if(s<=0)
 95         {
 96             printf("Case %d: Yes\n",tt);
 97             break;
 98         }
 99         int pt=0,vv=c;
100         for(int i=n;i>=1;i--)
101         {
102             if(!vis[i][vv])
103             {
104                 biaoji[i]=0;
105                 //v[i]=0;
106             }
107                 else
108             {
109                 biaoji[i]=1;vv=vv-v[i];
110                 v[i]=0;//把装过了的值赋为0
111             }
112 
113         }
114         }
115     }
116     return 0;
117 }

 

posted on 2013-08-24 22:08  plank george  阅读(154)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3