您的位置:首页 > 其它

poj 1014 || zoj 1149 Dividing

2012-12-08 16:41 489 查看
初看是一道dfs,果断敲下去。敲完之后才发现有点不对劲,接近20000*20000的时间规模很危险。

提交果然TLE了,多次优化之后还是TLE,发现是个多重背包


但又不想重敲,再从数学上想一下有没有什么优化的。

发现对于如果对于每一个marble如果数量为偶数,直接平分就可以了。由此推想,可否模一个数,令问题的规模缩小呢?

首先想到的就是2,但显然2是不可以的,对于6 0 0 0 0 1这组数据是可以平分的(6*1和1*6),但是如果模2之后,就变得不可以了。

所以推想到,剩余下来的值必然是用于填补更高级的值得不对称空白的。

接下来就设想,1要想填补6,就必须要有6个,所以要模6,同时当模的结果为0时,就设值为6 。(为了凑数)

所以就全部数模6之后计算了。果然0msAC了

#include <iostream>
#include <cstdio>

using namespace std;

int num[6] ;
int value[] = {1,2,3,4,5,6};
//int mods[] = {6,3,2,2,2,2};
int sums[6];
//target是需要填充的数值
bool dfs(int pos,int target)
{
if (target<0) return false;
if (target==0)  return true;
//当dfs到最后一个位置时,只需要判断剩下的1的数量能否填充需要就可以了
if (pos == 0)  return num[0]>=target;
for (int i = num[pos];i>=0;i--)
{
//当剩下的数值不足填充target时,就没有必要进行下去了
if (sums[pos-1]<target-i*value[pos]) return false;
if (dfs(pos-1,target-i*value[pos]))
{
return true;
}
}
return false;
}

int main()
{
int n=0;
while(1)
{
n++;
int sum = 0;
for(int i=0;i<6;i++) {
scanf("%d",&num[i]);
if (num[i]!=0){
num[i] = num[i]%6;
if (num[i]==0) num[i]=6;
}
sums[i] = num[i]*(i+1);
sum += sums[i];
}
for(int i=1;i<6;i++) {
sums[i] += sums[i-1] ;
}
if (sum==0) break;
bool can_divide = false;
if (sum %2 == 0)
{
can_divide = dfs(5,sum/2);
}
printf("Collection #%d:\n",n);
if (can_divide) printf("Can be divided.\n");
else
printf("Can't be divided.\n");
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: