您的位置:首页 > 其它

poj 1014 && zoj 1149 Dividing --- dfs剪枝

2014-02-11 23:00 323 查看
首先 dfs思路比较简单

目的是要凑出sum/2 贪心的想法 从价值大的往小的选 一次选的尽量多个

这样的话 方法是正确的 因为石子数量庞大 会超时 需要一个强有力的我永远都想不到的剪枝╮(╯▽╰)╭

某大神的想法:

以第一步选择价值为6的石子为例,如果接下去的选择价值为5的石子的数量超过6个,则我们可以用5个价值为6的石子替代;同样,如果再接下去的选择价值为4的石子的个子超过3个,我们也可以用2个价值为6的石子替代,依此类推。于是我们可以得到,在有足够的价值为6的石子的前提下,设选择6的个数为count,那么必须有(sum/2 - count*6)<=(5*5+4*2+3+2*2+5)= 45.也就是回溯时count减小到一定数量不满足以上不等式时就停止,这样将剪去大部分的无用的搜索。当然,接下去的选择5,4,3,。。。都如此。

#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#define inf 0x3f3f3f3f
#define ll __int64
using namespace std;

int gcm[]={0,1,6,14,40,45};
int w[10];

bool dfs(int v,int id)
{
    if(v==0) return 1;
    if(id<0) return 0;
    int cnt=min(v/(id+1),w[id]);
    v-=cnt*(id+1);
    while(cnt>=0)
    {
        if(dfs(v,id-1))
            return 1;
        cnt--;
        v+=(id+1);
        if(v>gcm[id])
            return 0;
    }
    return 0;
}

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