小木棍

题目

题解

1.分析:

此题可以理解为 “若干物品正好放入若干盒子的问题”;

对bfs的理解增加了:

初始状态为每个盒子都是空的,结尾状态为每个盒子都放好了,转移方法为“找一个物品放进去”,然后搜索就开始了

 2.大概思想题解都有了,讲讲自己的强调和补充:

a.这种小数据二分确实用处不大

b.很重要的一个剪枝:当前长棍剩余的未拼长度等于原始长度时,说明这根原来的长棍还一点没拼,现在正在放入一根木棍。很明显,这根木棍还没有跟其它棍子拼接,如果现在拼下去能成功话,它肯定是能用上的,即自组或与其它还没用的木棍拼接。但继续拼下去却失败,说明现在这根木棍不能用上,无法完成拼接,这跟木棍现在不用放到后面用也用不上,所以回溯改之前的木棍。

c.拼第k个木棍时,dfs中对于i类型木棒,能用就用完,这是错的(如代码)

for(int i = l; i <= kind; i++)
    {
        if(num[i] && len[i]<= res)
        {
            int tmp = min(num[i], res / len[i]);
            if(len[i] == res*tmp)//进入拼下一根木棍
            {
                num[i]-tmp;
                dfs(k+1, lenMg, 1);
                num[i]+=tmp;
                break;//如果恰好这么长行了,自动退出没毛病;如果恰好这么长都不行,比它短的来更不行了
                if(res == lenMg) return;//及其重要的一个剪枝(因为是第一根木棍,长的肯定要放在这里了)
            }
            else
            {
                num[i]-=tmp;
                dfs(k, res-len[i]*tmp, i);
                num[i]+=tmp;
                if(res == lenMg) return;//及其重要的一个剪枝
            }
        }
    }
View Code

原因:这是由链接题解中“几根组成x 比 1根x更灵活”的结论推出,但是这里5+5不一定能被2+2+2+2+2完全代替,因为有的时候大数字并不能被小数字拼出,比如5+4+1/4+3+3,这时候就不可能把两个4放在一起了

 

结尾放代码

#include<iostream>
#include<algorithm>
using namespace std;
int kind, len[100], num[100];//kind木棍, 第i种长len[i],第i种有Nump[i]根可用
int maxLen = 0, sum = 0;
int numMg, lenMg;//需要的木棍数,需要的木棍的长度
bool flag = 0;//标记找到答案没
void input()
{
    int n, a[100]= {0};
    cin >> n;
    while(n--)
    {
        int tmp;
        cin >> tmp;
        if(tmp <= 50)
        {
            a[++kind] = tmp;
            sum += tmp;
            maxLen = max(maxLen, tmp);
        }
    }
    n = kind;
    kind = 0;
    sort(a+1, a+1+n);
    for(int i = n; i >= 1; i--)
    {
        if(a[i] != len[kind])
        {
            kind++;
            len[kind] = a[i];
            num[kind] = 1;
        }
        else num[kind]++;
    }
    /*/cout test
    {
        cout <<kind<<":"<<endl;
        for(int i = 1; i <= kind; i++)
        {
            cout << len[i]<<" "<<num[i]<<endl;
        }
    }
    */
}
void dfs(int k, int res, int last)//正在拼第k根,第k根还有res的长度需要拼,上一次使用的木棍类型
{
    if(flag) return;
    if(k == numMg+1)
    {
        flag = 1;
        return;
    }
    /*
    int l=last, r=kind, mid;
    while(l<r){
        mid=(l+r)>>1;
        if(len[mid] <= res) r=mid;
        else l=mid+1;
    }
    */
    for(int i = last; i <= kind; i++)
    {
        if(num[i] && len[i]<= res)
        {
            if(len[i] == res)//进入拼下一根木棍
            {
                num[i]--;
                dfs(k+1, lenMg, 1);
                num[i]++;
                break;//如果恰好这么长行了,自动退出没毛病;如果恰好这么长都不行,比它短的来更不行了
                if(res == lenMg) return;
            }
            else
            {
                num[i]--;
                dfs(k, res-len[i], i);
                num[i]++;
                if(res == lenMg) return;
            }
        }
    }
}
int main()
{
    input();
    for(int i = maxLen; i <= sum/2; i++)
    {
        if(sum%i==0)
        {
            numMg = sum/i;
            lenMg = i;
            flag = 0;
            dfs(1, lenMg, 1);
            if(flag)
            {
                cout << i;
                return 0;
            }
        }
    }
    cout <<sum<<endl;
    return 0;
}
View Code

 

posted @ 2021-01-28 16:25  bear_xin  阅读(117)  评论(0)    收藏  举报