poj 1014 || zoj 1149 Dividing

来源:互联网 发布:郑州麻辣it 编辑:程序博客网 时间:2024/06/10 08:23

初看是一道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;}


原创粉丝点击