poj_2184_dp

题目描述:

   给出一个序列cow的属性值。对应cow的属性有smartness 和 funess。要求:在smartess和funess加和都大于0的条件下,sum of 这两个值最大的一个cow序列求出的sum值。

 

解题思路:

  对应于cow就是选或者不选两种可能,所以是0/1背包问题。对于这个问题,有两列值,不同于标准里的只有一个容量限制。等于我要求的是,按照smart为下标的数组,挨个加入一只cow,更新对应这个smart值的funess值最大可能是多少,最后做完背包更新,求大于0的那个smart数组的加和就可以了。

  那么在那个过程中,就要判断更新是正向还是反向进行(我们知道0/1里都是反向进行的,本质是怕更新重复。这里有负值,所以需要注意更新方向。)

 

代码:

#include<stdio.h>
#include <stdlib.h>
#define MIN -10000001
#define N 100001

int s[1001], f[1001];
int f1[N], f2[N], n;

main(){
   int i, v, min_st, max_st, tmp, max, j;
   scanf("%d",&n);
   min_st = 0;
   max_st = 0;
   for(i=1;i<=n;i++){
      scanf("%d %d",&s[i], &f[i]);
      if(s[i]<0)
         min_st += s[i];
      else
         max_st += s[i];
   }
   //printf("min_st:%d, max_st:%d\n",min_st, max_st);
   tmp = (0-min_st) > max_st? (0-min_st) : max_st;
   for(i=0;i<=tmp;i++){
      f2[i] = MIN;
      f1[i] = MIN;
   }

  
   for(i=1;i<=n;i++){
      if(s[i]>=0){ //反向更新
         for(v=max_st; v>=min_st+s[i]; v--){
            if(v>=0 && v-s[i]>=0 && f2[v-s[i]]!=MIN)
               f2[v] = f2[v-s[i]] + f[i] > f2[v] ? f2[v-s[i]] + f[i] : f2[v] ;
            if(v>=0 && v-s[i]<0 && f1[s[i]-v]!=MIN)
               f2[v] = f1[s[i]-v] + f[i] > f2[v] ? f1[s[i]-v] + f[i] : f2[v] ;
            if(v<0 && f1[s[i]-v]!=MIN)
               f1[0-v] = f1[s[i]-v] + f[i] > f1[0-v] ? f1[s[i]-v] + f[i] : f1[0-v] ;
         }
        
         if(f2[s[i]]<f[i])
            f2[s[i]] = f[i];
     
      }else{ //正向更新
         for(v=min_st; v<=max_st+s[i]; v++){
            if(v<0 && v-s[i]>=0 && f2[v-s[i]]!=MIN)
               f1[0-v] = f2[v-s[i]] + f[i] > f1[0-v] ? f2[v-s[i]] + f[i] : f1[0-v] ;
            if(v<0 && v-s[i]<0 && f1[s[i]-v]!=MIN)
               f1[0-v] = f1[s[i]-v] + f[i] > f1[0-v] ? f1[s[i]-v] + f[i] : f1[0-v] ;
            if(v>=0 && f2[v-s[i]]!=MIN)
               f2[v] = f2[v-s[i]] + f[i] > f2[v] ? f2[v-s[i]] + f[i] : f2[v] ;
         }
         if(f1[0-s[i]]<f[i])
            f1[0-s[i]] = f[i];
      }
     
//      printf("加完第%d组[%d,%d]后,数组为:\n",i,s[i],f[i]);
//      printf("f1:\n");
//      for(j=1;j<=(0-min_st);j++)
//         printf("%d\t",f1[j]);
//      printf("\nf2:\n");
//      for(j=0;j<=max_st;j++)
//         printf("%d\t",f2[j]);
//      printf("\n");

   }
   max = 0;
   for(i=0;i<=max_st;i++)
      if( f2[i]>=0 && i+f2[i] > max)
         max = i + f2[i];
  
   printf("%d\n",max);
  
   system("pause");
   return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值