zoukankan      html  css  js  c++  java
  • CQYZOJ P1392 拔河问题

    题目(1)

    Description

      一个学校举行拔河比赛,所有的人被分成了两组,每个人必须(且只能够)在其中的一组,且两个组内的所有人体重加起来尽可能地接近.

    Input

      第(1)行是一个(n),表示参加拔河比赛的总人数,(n<=100),接下来的n行表示第(1)到第(n)个人的体重,每个人的体重都是整数((1<=weight<=450))

    Output

      包含两个整数:分别是两个组的所有人的体重和,用一个空格隔开。注意如果这两个数不相等,则请把小的放在前面输出。

    Sample Input 1

    3
    100 90 200
    

    Sample Output 1

    190 200
    

    Hint

    (n<=100,1<=weight<=450)

    模型

    (0-1)背包

    解法

    转换成成一个花费(=)价值的(0-1)背包问题,记(F[i][j])为用前(i)个物品,总代价(<=j)能取得的最大价值,可得状态转移方程:

    [F[i][j]=max(F[i][j],F[i][j]-w[i]]+w[i]) ]

    最后答案即为(F[N][Sum/2]),其中(Sum=sum_{i=1}^Nw[i]).

    实际代码中,还可以使用滚动数组来优化空间.

    代码

    #include<bits/stdc++.h>
    using namespace std;
    
    #define MaxN 105
    #define Maxw 45005
    int w[MaxN],N;
    int F[Maxw];
    int Tx=0;
    
    int main()
    {
    	cin>>N;
    	for(int i=1;i<=N;i++)
    	{
    		cin>>w[i];
    		Tx+=w[i];
    	}
    	for(int i=1;i<=N;i++)
    		for(int P=Tx;P;P--)
    			if(P-w[i]>=0)
    				F[P]=max(F[P],F[P-w[i]]+w[i]);
    	cout<<F[Tx/2]<<" "<<Tx-F[Tx/2]<<endl;
    	return 0;
    }
    

    题目(2)

    Description

      一个学校举行拔河比赛,所有的人被分成了两组,每个人必须(且只能够)在其中的一组,两个队伍的人数之差不能超过1,且两个组内的所有人体重加起来尽可能地接近.

    Input

      第(1)行是一个(n),表示参加拔河比赛的总人数,(n<=100),接下来的n行表示第(1)到第(n)个人的体重,每个人的体重都是整数((1<=weight<=450))

    Output

      包含两个整数:分别是两个组的所有人的体重和,用一个空格隔开。注意如果这两个数不相等,则请把小的放在前面输出。

    Sample Input 1

    3
    100 90 200
    

    Sample Output 1

    190 200
    

    Hint

    (n<=100,1<=weight<=450)

    模型

    (0-1)背包

    解法

    同样转换成成一个花费(=)价值的(0-1)背包问题,记(F[i][j][k])为在前(i)个物品中选择(k)个,总代价(<=j)能取得的最大价值.可得状态转移方程:

    [F[i][j][k]=max(F[i][j][k],F[i-1][j-1][k-w[i]]+w[i]) ]

    最终答案即为(F[N][N/2][Sum]),其中(Sum=sum_{i=1}^Nw[i]).

    同样可以采用滚动数组优化,还要注意初始化边界.

    #include<bits/stdc++.h>
    using namespace std;
    #define INF 0x3f
    #define MaxN 105
    #define Maxw 45005
    int w[MaxN],N;
    int F[MaxN][Maxw];
    int Tx=0;
    
    int main()
    {
    	cin>>N;
    	for(int i=1;i<=N;i++)
    	{
    		cin>>w[i];
    		Tx+=w[i];
    	}
    	memset(F,-INF,sizeof(F));
    	for(int i=0;i<=Tx>>1;i++)
    		F[0][i]=0;
    	for(int i=1;i<=N;i++)
    		for(int j=i;j>=1;j--)
    			for(int P=Tx>>1;P>=w[i];P--)
    					F[j][P]=max(F[j][P],F[j-1][P-w[i]]+w[i]);
    					
    	int Ans=F[N>>1][Tx>>1];
    	if(N%2)
    		Ans=max(Ans,F[(N>>1)+1][Tx>>1]);		
    	cout<<Ans<<" "<<Tx-Ans<<endl;
    	return 0;
    }
    

    还要注意,本题中第三重循环必须从(Sum/2)开始,即代码中的

    for(int P=Tx>>1;P>=w[i];P--)
    

    否则会超时.

  • 相关阅读:
    MSN、易趣、大旗被挂马 用户浏览后感染机器狗病毒 狼人:
    世界最大漏洞数据库发布最新研究报告 狼人:
    五角大楼最昂贵武器发展项目遭到黑客攻击 狼人:
    RSA呼吁厂商“创造性协作” 共同反击网络威胁 狼人:
    RSA2009:云计算服务如何保证安全? 狼人:
    黑客工具可将恶意软件隐藏于.Net框架 狼人:
    RSA安全大会将亮相25款热门安全产品 狼人:
    目录访问共享C#怎么访问共享目录
    代码下行Jquery结合Ajax和Web服务使用三层架构实现无刷新分页
    输出次数HDU2192:MagicBuilding
  • 原文地址:https://www.cnblogs.com/TaylorSwift13/p/11172401.html
Copyright © 2011-2022 走看看