ural 1005

题目链接

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=93135#problem/B

题目大意

将一堆有重量的石头分成两组,使得两组石头总重量差额最小;等价于,从一堆有重量的石头中选出若干个,使得这些石头的重量最接近总重量的一半。

思路

暴力穷举之DFS

每个石头的状态是取或不取,最多20个石头,即2^20个状态;

存在隐式图:(类似于week 1,problem D)

从第一个石头开始构图,左边表示不取,有边表示取,值表示当前所取石头的总重量;第二个石头在第一个的两个选择下又分别有两个选择;第N个石头在第N-1个石头的各个选择下分别有取或不取两个选择;叶子节点的值即为可能的结果。

算法步骤

1.      读入数据,脑海里构图(完全二叉树);

2.      从虚拟根节点(0,0)开始DFS;如果高度等于数据量(number),得到一个分组结果;否则,递归DFS,如下图。

3.      输出结果。

算法复杂度

1.      每个石头均有取或不取两种选择,一共有N个石头,共有2^N个选择。时间复杂度为O(2^N)。

2.      空间复杂度O(N),储存数据的数据(每个石头的重量)。

提交状态

源代码

一维动态规划

典型的01背包问题

Number个物品(价值等于重量),背包容量为sum/2。

放第i个物品时:

1.背包剩余空间小于data[i],不放,背包重量不变。

2.否则,背包重量等于放与不放此物品的最大值。

算法步骤

1.      读入数据,存入data[]数组,并求出总质量的一半,即背包容量。

2.      开一个一维数组flag[],大小为背包容量加一,下标表示当前背包重量,值(0,1)若干个石头的组合可以使得背包达到这个重量,1表示可以,0表示不可以。初始化flag[0]=1;

3.      对于每一个石头,从背包容量开始,向0搜索。如果当前容量j>=data[i],flag为0,且flag[j – data[i] ]=1,则说明当前这个石头可以放进来。使得背包重量更大。

4.      石头遍历完,算法结束。得到flag[i]=1 的i的最大值,输出sum-2*i即可。

算法复杂度

1.      输入数据O(n);

2.      找出各种可能组合O(n*sum/2)。

3.      时间复杂度为O(n*sum/2)。

4.      空间复杂度体现在DP数组flag上,大小为sum/2+1;复杂度为O(sum/2);

 

源代码

dp

/*
典型的01背包问题
背包容量为总重量的一半
放进背包为A组,未放进为B组
结果 = 总重量减去A组两倍
*/
#include <iostream>
#include <vector>
using namespace std;


int main(int argc, char const *argv[])
{
    int number,sum=0,mid,ans=0;
    cin>>number;
    std::vector<int> data(number),flags;
    for (int i = 0; i < number; ++i)
    {
        cin>>data[i];   
        sum+=data[i];
    }
    mid=sum/2;


    flags.resize(mid+1,0);  flags[0]=1;
    for(int i=0;i<number;i++)
        for(int j=mid;j>=data[i];j--)  // 必须从最大开始
            if(!flags[j])
            {
                flags[j]=1;
                ans=max(ans,j);
            }


    cout<<sum-ans-ans<<endl;
    return 0;
}


dfs

/*
暴力搜索 2^20 存在一个隐式图  类似于上周 1212 的广搜
*/
#include <iostream>
#include <stdlib.h>
#include <vector>
using namespace std;


std::vector<int> data;
int sum=0,number,ans=1e9;


void DFS(int high, int weight)
{
if(high==number)
{
ans = min(ans,abs((sum - weight) - weight));
return;
}
DFS(high+1,weight);
DFS(high+1,weight+data[high+1]);
}


int main(int argc, char const *argv[])
{
cin>>number;
data.resize(number);
for(int i=0;i<number;i++)
{
cin>>data[i];
sum+=data[i];
}
DFS(0,0);
cout<<ans<<endl;
return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值