题意:

  两个人共同收藏了一些石头,现在要分道扬镳,得分资产了,石头具有不同的收藏价值,分别为1、2、3、4、5、6共6个价钱。问:是否能公平分配?

输入:

  每行为一个测试例子,每行包括6个数字,分别对应6种价钱的石头数目,比如101200代表价值为1的石头有1个,价值为2的石头有0个....价值为4的石头有2个。他们具有的石头数量的上限为2万个。

思路:

  想用多重背包的方式解决,也想转01背包比较简单。直接转01背包会超时,得想办法。可以用多重背包的方法,用二进制来减少复杂度,应该可行。我用的是偷懒的办法,将数据都减小,比如某个价值的石头有1千个,是偶数,那就可以直接分掉,每人500啦,但是可能会有奇数个的情况,所以不能单独将某价值的石头一次性分完。那么留多少合适?我觉得留4合适,但是实际上留了8个以下才能AC。

出现下面情况说明了不能将某个价值的石头总数mod2:

价值:1 2 3 4 5 6

数量:1 0 8 0 1 0

解释:假如%2的话,价值为3的石头就变为0个,剩下两个石头,价值分别为1和5,分不了!

所以余数必须大于2,测试了一下,6不行,8以上的偶数就行了。

现在,数据的大小降下来了,转成01背包就简单多了。将剩下的所有石头的的价值的一半假设为背包的容量,将石头的体积设为等价于其价值大小。什么意思呢?

举个例子:

价值:1 2 3 4 5 6

数量:1 0 2 0 1 0

体积:1 2 3 4 5 6

假设这是数值大小降低后的结果,一眼可以看出1+5=3*2,可以公平分配,所有石头的总价值为12,假设其中一个人是我,那么我必须分配到价值为6的石头才是公平的,不用管到底分得1块还是2块石头。而其价值与体积已经假设是相等的,那么设我的背包大小为6,我想从这些石头(4块)中挑出一些石头,使我的背包装满,只要能刚好装满,证明能公平分配,即dp[x]=x。 这个可列举一些小的数据后计算就能验证。

 #include <iostream>
using namespace std;
int num[];
int dp[];
bool divide(int sum)
{
int k,i,j;
for(i=;i<;i++)
for(k=;k<num[i];k++)
for(j=sum;j>i;j--)
if(dp[j-(i+)]+(i+)>dp[j])
dp[j]=dp[j-(i+)]+(i+);
if(dp[sum]==sum)
return true;
else
return false;
}
int main()
{
int i,n=,sum;
while()
{
for(i=,sum=;i<;i++)
{
scanf("%d",&num[i]);
num[i]%=;
sum+=num[i]*(i+); //所有石头的价值总和
}
if(!num[]&&!num[]&&!num[]&&!num[]&&!num[]&&!num[]) return ; //全0就退出
if(sum%!=) //价值的总和不能被被2整除的话就肯定分不了
{
printf("Collection #%d:\nCan't be divided.\n\n",++n);
continue;
}
else sum>>=; //可以分的话,总和得减半
memset(dp,,sizeof(int)*(sum+)); //清内存
if(divide(sum)==true)
printf("Collection #%d:\nCan be divided.\n\n",++n);
else
printf("Collection #%d:\nCan't be divided.\n\n",++n);
}
return ;
}

1059

另一解法:使用普通型母函数。

思路:同样需要将数据降小,好像不一定对于这样的题都可以进行数据降小处理,但是这里可以就方便多了。母函数主要算的是组成某一种值的方法数,既然有组成的方法,那肯定是能公平分配了,可能还不止一种公平的分配方法呢。利用这点,我们不需要求出分配一半价值的所有方法,只需在检测出有一种方法就可以返回了,无需继续算。

代码思路:用笔算的话我们能算出来,其实方法就是模拟我们的笔算方法,有六种价值,那么就只有6个括号要相乘。而每个括号中的幂次数最多为价值的一半即可,我们要求的就是组成一半价值的方法。

看代码还是容易点吧,代码这么多是因为大部分是固定的模版啊!

 #include <iostream>
#include <cstring>
#define N 100
using namespace std;
int num[];
int ans[N]; //
int sup[N];
bool divide(int sum) //取部分石头,能组成价值为sum,证明可公平分配。
{
int k,i,j;
for(i=;i<=;i++) //作6个括号相乘
{
if(num[i-]==) continue;
for(j=;j<=sum&&j<=num[i-]*i;j+=i) //j是跳的,间距是i
for(k=;k<=sum;k++)
sup[j+k]+=ans[k]; //重点在这,好好理解
memcpy(ans,sup,sizeof(int)*(sum+)); //这样复制更快
memset(sup,,sizeof(sup)); //这样清零更快
if(ans[sum]>) return true; //有1种方法以上都可以返回了
}
return false;
}
int main()
{
int i,n=,sum;
while()
{
for(i=,sum=;i<;i++)
{
scanf("%d",&num[i]);
num[i]%=; //数值降小
sum+=num[i]*(i+); //所有石头的价值总和(已降)
}
if(!num[]&&!num[]&&!num[]&&!num[]&&!num[]&&!num[]) return ; //全0就退出
if(sum%!=) //价值的总和不能被被2整除的话就肯定分不了
{
printf("Collection #%d:\nCan't be divided.\n\n",++n);
continue;
}
else sum>>=; //可以分的话,总和得减半
//**********以上部分是固定的****************************************
memset(ans,,sizeof(ans)); //清内存
memset(sup,,sizeof(sup)); //清内存
for(i=;i<=num[];i++) //初始化ans
ans[i]=;
if(divide(sum)==true)
printf("Collection #%d:\nCan be divided.\n\n",++n);
else
printf("Collection #%d:\nCan't be divided.\n\n",++n);
}
}

1059

HDU 1059 Dividing 分配(多重背包,母函数)的更多相关文章

  1. HDOJ(HDU).1059 Dividing(DP 多重背包+二进制优化)

    HDOJ(HDU).1059 Dividing(DP 多重背包+二进制优化) 题意分析 给出一系列的石头的数量,然后问石头能否被平分成为价值相等的2份.首先可以确定的是如果石头的价值总和为奇数的话,那 ...

  2. hdu 1059 Dividing bitset 多重背包

    bitset做法 #include <bits/stdc++.h> #define PI acos(-1.0) #define mem(a,b) memset((a),b,sizeof(a ...

  3. 题解报告:hdu 1059 Dividing(多重背包、多重部分和问题)

    Problem Description Marsha and Bill own a collection of marbles. They want to split the collection a ...

  4. HDU 1059 Dividing(多重背包)

    点我看题目 题意: 将大理石的重量分为六个等级,每个等级所在的数字代表这个等级的大理石的数量,如果是0说明这个重量的大理石没有.将其按重量分成两份,看能否分成. 思路 :一开始以为是简单的01背包,结 ...

  5. HDOJ(HDU).2844 Coins (DP 多重背包+二进制优化)

    HDOJ(HDU).2844 Coins (DP 多重背包+二进制优化) 题意分析 先把每种硬币按照二进制拆分好,然后做01背包即可.需要注意的是本题只需要求解可以凑出几种金钱的价格,而不需要输出种数 ...

  6. hdu 1059 Dividing(多重背包优化)

    Dividing Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Su ...

  7. Hdu 1059 Dividing & Zoj 1149 & poj 1014 Dividing(多重背包)

    多重背包模板- #include <stdio.h> #include <string.h> int a[7]; int f[100005]; int v, k; void Z ...

  8. ACM学习历程—HDU 1059 Dividing(dp && 多重背包)

    Description Marsha and Bill own a collection of marbles. They want to split the collection among the ...

  9. hdu2110(多重背包/母函数)

    http://acm.hdu.edu.cn/showproblem.php?pid=2110 就是个多重背包,有坑点-.-.注意答案模10000中间结果有可能会爆所以计算时就要取模: 由于必须能均分三 ...

随机推荐

  1. 关闭QtCreator的vim风格编辑模式

    今天不小心点到了键盘的快捷键Alt+V,使QtCreator进入了vim风格编辑模式,导致快捷键拷贝粘贴都不正常,找了下资料才发现是这个问题.具体操作如下: 打开QtCreator去掉下列位置的勾选或 ...

  2. SQL 动态拼接SQL 语句

    USE [PMS_UnifiedDB_15] GO /****** Object: StoredProcedure [dbo].[SP_GetLogInfo] Script Date: 2/11/20 ...

  3. 转:基础篇|PHP如何解决网站大流量和高并发

    基础篇 高并发架构基础概念和优化思路 高并发架构相关概念 并发,在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程 ...

  4. CAS客户端整合(三) Otrs

    OTRS 是用Perl写的一个工单邮件系统,非常强大. 登录流程 流程图略过 otrs没有像 discuz 和 zabbix 类似的游客登录状态,这样处理起来逻辑分支少一些. 不过还是考虑用 otrs ...

  5. mysql之SQL入门与提升(二)

    在mysql之SQL入门与提升(一)我们已经有了些许基础,今天继续深化 先造表 SET NAMES utf8;SET FOREIGN_KEY_CHECKS = 0; -- -------------- ...

  6. IPv6邻居发现协议

    IPv6邻居发现协议 邻居发现协议NDP 邻居发现协议NDP(Neighbor Discovery Protocol)是IPv6协议体系中一个重要的基础协议.邻居发现协议替代了IPv4的ARP(Add ...

  7. tomcat memecached session 共享同步问题的解决

    事件缘由:一个主项目“图说美物”,另外一个子功能是品牌商的入驻功能,是跟主项目分开的项目,为了共享登录的用户信息,而实现session共享,俩个tomcat,一个tomcat6,一个tomcat7 w ...

  8. myeclipse编辑jsp页面卡

    现象 但是遇到了一种情况,编辑jsp页面卡,尤其是使用快捷键ctrl+ 时会很卡. 编辑java页面没问题的,比较流畅. 在jsp页面中一点ctrl+  就卡几秒钟. 按照上篇文章中优化过后只是编辑j ...

  9. LeetCode 232 Implement Queue using Stacks 两个栈实现队列

    class MyQueue { public: /** Initialize your data structure here. */ MyQueue() { } /** Push element x ...

  10. postgis 赋予postgresql空间数据库的能力

    安装: Windows:postgresql的bin目录下:运行stackbuilder,一步一步按照提示来就行了 Ubuntu: apt-get install postgresql-9.3-pos ...