UVa 307 スティック 木製スティック スプライシング ID 反復深化検索

質問リンク:スティックの
質問の説明:

シャオ ミンは、最初は同じ長さの木の棒をいくつか持っていました。シャオ ミンは今、その木の棒を切り刻んで、整数の長さの木の棒を作ります。彼は今、元の木の棒の長さを忘れています。可能な限り短い木の棒の長さを見つける必要があります。たとえば、与えられた場合5 , 2 , 1 , 5 , 2 , 1 , 5 , 2 , 1 5,2,1,5,2,1,5,2,1 を決定します。5 2 1 5 2 1 5 2 1すると、これらの木の棒は24 24の長さで作ることができます。木の棒は24 本ですが、 12 12の 2 つの長さにすることもできます。12本の棒を切り出すか、8 88スティックから4 4にもなることが4 の長さは6 66本の棒が切り出されました。うち6 66は最短の長さです。666

答え:

この質問では最初に木の棒が何本あるかわからないため、実際には木の棒の最初の数を逆順に列挙することができます ( nnから)最初のスティックの数が多いほどスティックの長さが短くなるため、 nから開始し、すべての状況を順番に検索します。これはID IDの逆順です。IDアルゴリズム(通常はID IDID はすべて正の列挙です)。
この質問の難しいところは、どうやって検索するかです。初期の木の棒の数を数えると、各初期の木の棒の長さ、つまり木の棒の長さの合計を初期の木の棒の数で割った値がわかり、木の棒の長さを分類することができます。初めて組み合わせる木の棒を選ぶときは、長い木の棒を優先して、現在の木の棒に継ぎ合わせていきますが、最初の木の棒の長さよりも長い場合は、続けて組み合わせることができます。処理用に小さい木の棒を選択します。最初の木の棒の長さと正確に等しい場合は、組み合わせるためにいくつかの短い木の棒を選択するのではなく、現在の木の棒と組み合わせるためにそれを選択する必要があります。いくつかの短い木の棒を選択します。すると、残りの棒の柔軟性が低下します。そして、この棒を組み合わせに選択すると、残りの棒にはより多くの組み合わせの可能性があり、これはまた、継ぎ合わせに 1 本の棒を選択すると、それが正確に一致することを示しています。場合によっては、検索に失敗した場合、短いスティックを選択した場合でも検索が失敗することがあります。

コード:

#include <bits/stdc++.h>

using namespace std;

int n, maxDepth, sum;
vector<int> len;
bool *used;

bool dfs(int nowDepth, int nowLen, int pos)
{
    
    
    if (nowDepth == maxDepth) {
    
     return true; }
    for (int i = pos; i >= 0; i--) {
    
    
        if (used[i]) {
    
     continue; }
        if (nowLen + len[i] < sum / maxDepth) {
    
    
            used[i] = true;
            if (dfs(nowDepth, nowLen + len[i], i - 1)) {
    
     return true; }
            used[i] = false;
            while (i - 1 >= 0 && len[i - 1] == len[i]) {
    
     i--; } // 相同长度此时一定会失败
        } else if (nowLen + len[i] == sum / maxDepth) {
    
    
            used[i] = true;
            if (dfs(nowDepth + 1, 0, n - 1)) {
    
     return true; }
            used[i] = false;
            return false; // 没有必要选择更短的,因为灵活性更低了
        }
        if (nowLen == 0) {
    
     return false; } // 这里是为了防止重复搜索
    }
    return false;
}

int main()
{
    
    
    while (cin >> n && n != 0) {
    
    
        len.resize(n);
        used = new bool[n]; // 这题没有告知数据范围,所以这里采用了动态内存分配
        sum = 0;
        for (int i = 0; i < n; i++) {
    
    
            cin >> len[i];
            sum += len[i];
        }
        sort(len.begin(), len.end());
        for (maxDepth = n; ;maxDepth--) {
    
    
            if (sum % maxDepth != 0 || len[n - 1] > sum / maxDepth) {
    
     continue; }
            memset(used, 0, sizeof(bool) * n);
            if (dfs(0, 0, n - 1)) {
    
     break; }
        }
        cout << sum / maxDepth << endl;
        delete used;
    }
    return 0;
}

おすすめ

転載: blog.csdn.net/qq_45523675/article/details/129326265