zoukankan      html  css  js  c++  java
  • dp背包之01背包poj2184

    http://poj.org/problem?id=2184

    题意:给定两个属性,求这两个属性的和的最大值.........

    思路:将第一个属性往后平移1000个单位,然后推导其动态转移方程,若是dp[i],代表当加入第一个属性加到i时,符合题意的第二个属性的最大值......题意是两个属性的和的最大值,那么动态转移方程必然不是dp[j]=max(dp[j],dp[j-s[i][0]]+s[i][1]),因为这个动态转移方程固然可以求出第二个属性的最大值,但别忘了题意要求第一个属性与第二个属性的和的最大值,那么,第一个属性平移了1000个单位,在考虑动态转移时,是必须要将这个考虑进去的。可以开一个a数组记录路径,然后根据题意,
    动态转移方程应该为dp[j]=max(dp[j]-a[j]*1000,dp[j-s[i][0]]+s[i][1]-(a[j-s[i][0]]+1)*1000),一开始a数组全部赋值为0,所以需要a[j-s[i][0]]+1.....因为它新加入了一个值。考虑这个方程,dp数组的初始全部赋值为负无穷大,dp[0]=0。

    注意一点,在历遍查找最大值的时候,dp[i]>0,i-a[i]*1000>0

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    using namespace std; 
    #define maxx 1000005
    int s[maxx][2],dp[maxx],a[maxx];
    int main()
    {
    	int n;
    	while(scanf("%d",&n)>0)
    	{
    		int sum=0;
    		for(int i=1;i<=n;i++)
    		{
    			scanf("%d %d",&s[i][0],&s[i][1]);
    			if(s[i][0]<0&&s[i][1]<0)
    			{
    				i--;
    				n--;
    				continue;
    			}
    			s[i][0]+=1000;
    			sum+=s[i][0];
    		}
    		memset(a,0,sizeof(a));
    		for(int i=0;i<=sum;i++)
    		dp[i]=-maxx;
    		dp[0]=0;
    		for(int i=1;i<=n;i++)
    		{
    			for(int j=sum;j>=s[i][0];j--)
    			if(dp[j]-a[j]*1000<dp[j-s[i][0]]+s[i][1]-(a[j-s[i][0]]+1)*1000)
    			{
    				dp[j]=dp[j-s[i][0]]+s[i][1];
    				a[j]=a[j-s[i][0]]+1;
    			}
    		}
    		int maxn=0;
    		for(int i=1;i<=sum;i++)
    		if(maxn<dp[i]-a[i]*1000+i&&dp[i]>=0&&i-a[i]*1000>=0)
    		maxn=dp[i]-a[i]*1000+i;
    		printf("%d
    ",maxn);
    	}
    	return 0;
    }
    
  • 相关阅读:
    JavaScript作用域
    原生JS判断作用域输出值
    用原生JS写九九乘法表
    用原生JS写冒泡排序及动画演示
    用原生JS写翻转数组
    用原生JS写星星直角三角形
    rabbitmq系列——(5 消息确认 -- 生产者 事务性消息)
    rabbitmq系列——(5 消息确认 -- 消费者 自动确认和手动确认)
    rabbitmq系列——(6 消息队列集群)
    docker 发布 dotnet3.1 web
  • 原文地址:https://www.cnblogs.com/ziyi--caolu/p/3203513.html
Copyright © 2011-2022 走看看