DFS + 剪枝

题目详情 - L3-2 还原文件 (30 分) (pintia.cn)

代码:这道题目可以当做dfs来做(很多得26分的情况就是少判断了一种条件 例如 2 4 6 8 9 2 4 6,3个序列分别是:2 4 6 | 9 | 2 4 6 8当你判断到2 4 6觉得是第一个序列时,其实是2 4 6 8,但是它却是另一个序列,你并没有关心下一个是否匹配成功,就会陷入死循环),所以用dfs判断至最后一个元素时结束,当当前序列匹配成功时,对应总序列位置转移cnt+s[i].size()-1,再回溯,还需要用st数组来判断该序列是否被用过

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

const int N = 100010;

int n, m, w[N], idx;
vector<int> g[N];
vector<int> res, now;
bool has_answer, st[N];

void dfs(int u) //u表示当前位于的位置
{
    if(u >= n - 1)//因为下面的减一操作,这里也要减一
    {
        res = now;
        has_answer = true;
        return ;
    }

    if(has_answer)  //剪枝,如果已经搜索到答案,后面就不用搜索了  
        return ;
    
    for(int i = 1; i <= m; i ++ )
    {
        if(!st[i])
        {
            bool flag = true;
            for(int j = 0; j < g[i].size(); j ++ )  //匹配所有高度
            {
                if(g[i][j] != w[u + j])
                {
                    flag = false;
                    break;
                }
            }
            if(flag)
            {
                st[i] = true;
                now.push_back(i);
                dfs(u + g[i].size() - 1);//之所以减一是因为两片碎纸会共用一个高度
                
                st[i] = false;
                now.pop_back();
            }
        }
    }
}

int main()
{
    cin >> n;
    for(int i = 0; i < n; i ++ )   cin >> w[i];
    
    cin >> m;
    for(int i = 1; i <= m; i ++ )
    {
        int k;  cin >> k;
        while(k -- )
        {
            int x;  cin >> x;
            g[i].push_back(x);
        }
    }
    
    dfs(0);//从第0个折线高度开始匹配
    
    // cout << res.size() << endl;
    for(int i = 0; i < res.size(); i ++ )
    {
        cout << res[i];
        if(i != res.size() - 1) cout << " ";
    }
    
    return 0;
}

posted @ 2022-05-05 08:41  光風霽月  阅读(15)  评论(0编辑  收藏  举报